summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-02 01:32:20 +0000
committergman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-02 01:32:20 +0000
commit0d6bfdcdb3e18a84979ff9be88da7ddcd68526ec (patch)
tree0e4d33bded0601ac73434c2b24acc93477becd6d
parent1314341944011bcfff64f32e7db86d27e574c048 (diff)
downloadchromium_src-0d6bfdcdb3e18a84979ff9be88da7ddcd68526ec.zip
chromium_src-0d6bfdcdb3e18a84979ff9be88da7ddcd68526ec.tar.gz
chromium_src-0d6bfdcdb3e18a84979ff9be88da7ddcd68526ec.tar.bz2
Defer clearing textures and renderbuffers
Textures and Renderbuffers are now cleared at the last possible moment. This allows them to be cleared only when absolutely necessary. TEST=unit tests BUG=99554 Review URL: http://codereview.chromium.org/8341128 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@108226 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--gpu/command_buffer/service/framebuffer_manager.cc124
-rw-r--r--gpu/command_buffer/service/framebuffer_manager.h31
-rw-r--r--gpu/command_buffer/service/framebuffer_manager_unittest.cc263
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc368
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.h12
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_mock.h9
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc682
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc24
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc291
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h178
-rw-r--r--gpu/command_buffer/service/renderbuffer_manager.cc42
-rw-r--r--gpu/command_buffer/service/renderbuffer_manager.h40
-rw-r--r--gpu/command_buffer/service/renderbuffer_manager_unittest.cc19
-rw-r--r--gpu/command_buffer/service/texture_manager.cc276
-rw-r--r--gpu/command_buffer/service/texture_manager.h73
-rw-r--r--gpu/command_buffer/service/texture_manager_unittest.cc209
16 files changed, 2066 insertions, 575 deletions
diff --git a/gpu/command_buffer/service/framebuffer_manager.cc b/gpu/command_buffer/service/framebuffer_manager.cc
index 909a451..0ce9df07 100644
--- a/gpu/command_buffer/service/framebuffer_manager.cc
+++ b/gpu/command_buffer/service/framebuffer_manager.cc
@@ -13,34 +13,36 @@ class RenderbufferAttachment
: public FramebufferManager::FramebufferInfo::Attachment {
public:
explicit RenderbufferAttachment(
- RenderbufferManager::RenderbufferInfo* render_buffer)
- : render_buffer_(render_buffer) {
+ RenderbufferManager::RenderbufferInfo* renderbuffer)
+ : renderbuffer_(renderbuffer) {
}
virtual ~RenderbufferAttachment() { }
virtual GLsizei width() const {
- return render_buffer_->width();
+ return renderbuffer_->width();
}
virtual GLsizei height() const {
- return render_buffer_->height();
+ return renderbuffer_->height();
}
virtual GLenum internal_format() const {
- return render_buffer_->internal_format();
+ return renderbuffer_->internal_format();
}
virtual GLsizei samples() const {
- return render_buffer_->samples();
+ return renderbuffer_->samples();
}
virtual bool cleared() const {
- return render_buffer_->cleared();
+ return renderbuffer_->cleared();
}
- virtual void set_cleared() {
- render_buffer_->set_cleared();
+ virtual void SetCleared(
+ RenderbufferManager* renderbuffer_manager,
+ TextureManager* /* texture_manager */) {
+ renderbuffer_manager->SetCleared(renderbuffer_);
}
virtual bool IsTexture(TextureManager::TextureInfo* /* texture */) const {
@@ -51,12 +53,21 @@ class RenderbufferAttachment
return true;
}
- RenderbufferManager::RenderbufferInfo* render_buffer() const {
- return render_buffer_.get();
+ virtual void DetachFromFramebuffer() {
+ // Nothing to do for renderbuffers.
+ }
+
+ virtual bool ValidForAttachmentType(GLenum attachment_type) {
+ // TODO(gman): Fill this out.
+ return true;
+ }
+
+ RenderbufferManager::RenderbufferInfo* renderbuffer() const {
+ return renderbuffer_.get();
}
private:
- RenderbufferManager::RenderbufferInfo::Ref render_buffer_;
+ RenderbufferManager::RenderbufferInfo::Ref renderbuffer_;
DISALLOW_COPY_AND_ASSIGN(RenderbufferAttachment);
};
@@ -99,12 +110,13 @@ class TextureAttachment
}
virtual bool cleared() const {
- // Textures are cleared on creation.
- return true;
+ return texture_->IsLevelCleared(target_, level_);
}
- virtual void set_cleared() {
- NOTREACHED();
+ virtual void SetCleared(
+ RenderbufferManager* /* renderbuffer_manager */,
+ TextureManager* texture_manager) {
+ texture_manager->SetLevelCleared(texture_, target_, level_);
}
virtual bool IsTexture(TextureManager::TextureInfo* texture) const {
@@ -119,6 +131,15 @@ class TextureAttachment
return texture_->CanRenderTo();
}
+ virtual void DetachFromFramebuffer() {
+ texture_->DetachFromFramebuffer();
+ }
+
+ virtual bool ValidForAttachmentType(GLenum attachment_type) {
+ // TODO(gman): Fill this out.
+ return true;
+ }
+
private:
TextureManager::TextureInfo::Ref texture_;
GLenum target_;
@@ -133,15 +154,24 @@ FramebufferManager::~FramebufferManager() {
DCHECK(framebuffer_infos_.empty());
}
+void FramebufferManager::FramebufferInfo::MarkAsDeleted() {
+ service_id_ = 0;
+ while (!attachments_.empty()) {
+ Attachment* attachment = attachments_.begin()->second.get();
+ attachment->DetachFromFramebuffer();
+ attachments_.erase(attachments_.begin());
+ }
+}
+
void FramebufferManager::Destroy(bool have_context) {
while (!framebuffer_infos_.empty()) {
- if (have_context) {
- FramebufferInfo* info = framebuffer_infos_.begin()->second;
- if (!info->IsDeleted()) {
+ FramebufferInfo* info = framebuffer_infos_.begin()->second;
+ if (!info->IsDeleted()) {
+ if (have_context) {
GLuint service_id = info->service_id();
glDeleteFramebuffersEXT(1, &service_id);
- info->MarkAsDeleted();
}
+ info->MarkAsDeleted();
}
framebuffer_infos_.erase(framebuffer_infos_.begin());
}
@@ -158,8 +188,8 @@ void FramebufferManager::CreateFramebufferInfo(
}
FramebufferManager::FramebufferInfo::FramebufferInfo(GLuint service_id)
- : service_id_(service_id)
- , has_been_bound_(false) {
+ : service_id_(service_id),
+ has_been_bound_(false) {
}
FramebufferManager::FramebufferInfo::~FramebufferInfo() {}
@@ -175,12 +205,14 @@ bool FramebufferManager::FramebufferInfo::HasUnclearedAttachment(
return false;
}
-void FramebufferManager::FramebufferInfo::MarkAttachedRenderbuffersAsCleared() {
+void FramebufferManager::FramebufferInfo::MarkAttachmentsAsCleared(
+ RenderbufferManager* renderbuffer_manager,
+ TextureManager* texture_manager) {
for (AttachmentMap::iterator it = attachments_.begin();
it != attachments_.end(); ++it) {
Attachment* attachment = it->second;
if (!attachment->cleared()) {
- attachment->set_cleared();
+ attachment->SetCleared(renderbuffer_manager, texture_manager);
}
}
}
@@ -204,18 +236,52 @@ GLenum FramebufferManager::FramebufferInfo::GetColorAttachmentFormat() const {
return attachment->internal_format();
}
-bool FramebufferManager::FramebufferInfo::IsNotComplete() const {
+GLenum FramebufferManager::FramebufferInfo::IsPossiblyComplete() const {
+ if (attachments_.empty()) {
+ return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
+ }
+
+ GLsizei width = -1;
+ GLsizei height = -1;
for (AttachmentMap::const_iterator it = attachments_.begin();
it != attachments_.end(); ++it) {
+ GLenum attachment_type = it->first;
Attachment* attachment = it->second;
- if (attachment->width() == 0 || attachment->height() == 0) {
- return true;
+ if (!attachment->ValidForAttachmentType(attachment_type)) {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ if (width < 0) {
+ width = attachment->width();
+ height = attachment->height();
+ if (width == 0 || height == 0) {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ } else {
+ if (attachment->width() != width || attachment->height() != height) {
+ return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
+ }
}
+
if (!attachment->CanRenderTo()) {
- return true;
+ return GL_FRAMEBUFFER_UNSUPPORTED;
}
}
- return false;
+
+ // This does not mean the framebuffer is actually complete. It just means our
+ // checks passed.
+ return GL_FRAMEBUFFER_COMPLETE;
+}
+
+bool FramebufferManager::FramebufferInfo::IsCleared() const {
+ // are all the attachments cleaared?
+ for (AttachmentMap::const_iterator it = attachments_.begin();
+ it != attachments_.end(); ++it) {
+ Attachment* attachment = it->second;
+ if (!attachment->cleared()) {
+ return false;
+ }
+ }
+ return true;
}
FramebufferManager::FramebufferInfo* FramebufferManager::GetFramebufferInfo(
diff --git a/gpu/command_buffer/service/framebuffer_manager.h b/gpu/command_buffer/service/framebuffer_manager.h
index 737dfff..78b3e2f 100644
--- a/gpu/command_buffer/service/framebuffer_manager.h
+++ b/gpu/command_buffer/service/framebuffer_manager.h
@@ -35,9 +35,13 @@ class FramebufferManager {
virtual GLenum internal_format() const = 0;
virtual GLsizei samples() const = 0;
virtual bool cleared() const = 0;
- virtual void set_cleared() = 0;
+ virtual void SetCleared(
+ RenderbufferManager* renderbuffer_manager,
+ TextureManager* texture_manager) = 0;
virtual bool IsTexture(TextureManager::TextureInfo* texture) const = 0;
virtual bool CanRenderTo() const = 0;
+ virtual void DetachFromFramebuffer() = 0;
+ virtual bool ValidForAttachmentType(GLenum attachment_type) = 0;
};
explicit FramebufferInfo(GLuint service_id);
@@ -58,7 +62,9 @@ class FramebufferManager {
GLenum attachment, TextureManager::TextureInfo* texture, GLenum target,
GLint level);
- void MarkAttachedRenderbuffersAsCleared();
+ void MarkAttachmentsAsCleared(
+ RenderbufferManager* renderbuffer_manager,
+ TextureManager* texture_manager);
const Attachment* GetAttachment(GLenum attachment) const;
@@ -78,11 +84,17 @@ class FramebufferManager {
bool HasStencilAttachment() const;
GLenum GetColorAttachmentFormat() const;
- // We can't know if the frame buffer is complete since that is
- // implementation dependent and we'd have to check after every glTexImage
- // call but we can know in certain cases that it's NOT complete which we
- // need to enforce the OpenGL ES 2.0 spec on top of DesktopGL.
- bool IsNotComplete() const;
+ // Verify all the rules in OpenGL ES 2.0.25 4.4.5 are followed.
+ // Returns GL_FRAMEBUFFER_COMPLETE if there are no reasons we know we can't
+ // use this combination of attachments. Otherwise returns the value
+ // that glCheckFramebufferStatus should return for this set of attachments.
+ // Note that receiving GL_FRAMEBUFFER_COMPLETE from this function does
+ // not mean the real OpenGL will consider it framebuffer complete. It just
+ // means it passed our tests.
+ GLenum IsPossiblyComplete() const;
+
+ // Check all attachments are cleared
+ bool IsCleared() const;
private:
friend class FramebufferManager;
@@ -90,10 +102,7 @@ class FramebufferManager {
~FramebufferInfo();
- void MarkAsDeleted() {
- service_id_ = 0;
- attachments_.clear();
- }
+ void MarkAsDeleted();
// Service side framebuffer id.
GLuint service_id_;
diff --git a/gpu/command_buffer/service/framebuffer_manager_unittest.cc b/gpu/command_buffer/service/framebuffer_manager_unittest.cc
index bdf5d15..264245f 100644
--- a/gpu/command_buffer/service/framebuffer_manager_unittest.cc
+++ b/gpu/command_buffer/service/framebuffer_manager_unittest.cc
@@ -12,11 +12,21 @@ namespace gpu {
namespace gles2 {
class FramebufferManagerTest : public testing::Test {
+ static const GLint kMaxTextureSize = 64;
+ static const GLint kMaxCubemapSize = 64;
+ static const GLint kMaxRenderbufferSize = 64;
+ static const GLint kMaxSamples = 4;
+
public:
- FramebufferManagerTest() {
+ FramebufferManagerTest()
+ : texture_manager_(kMaxTextureSize, kMaxCubemapSize),
+ renderbuffer_manager_(kMaxRenderbufferSize, kMaxSamples) {
+
}
~FramebufferManagerTest() {
manager_.Destroy(false);
+ texture_manager_.Destroy(false);
+ renderbuffer_manager_.Destroy(false);
}
protected:
@@ -33,8 +43,17 @@ class FramebufferManagerTest : public testing::Test {
// Use StrictMock to make 100% sure we know how GL will be called.
scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
FramebufferManager manager_;
+ TextureManager texture_manager_;
+ RenderbufferManager renderbuffer_manager_;
};
+// GCC requires these declarations, but MSVC requires they not be present
+#ifndef COMPILER_MSVC
+const GLint FramebufferManagerTest::kMaxTextureSize;
+const GLint FramebufferManagerTest::kMaxCubemapSize;
+const GLint FramebufferManagerTest::kMaxRenderbufferSize;
+#endif
+
TEST_F(FramebufferManagerTest, Basic) {
const GLuint kClient1Id = 1;
const GLuint kService1Id = 11;
@@ -82,11 +101,20 @@ class FramebufferInfoTest : public testing::Test {
static const GLuint kClient1Id = 1;
static const GLuint kService1Id = 11;
+ static const GLint kMaxTextureSize = 64;
+ static const GLint kMaxCubemapSize = 64;
+ static const GLint kMaxRenderbufferSize = 64;
+ static const GLint kMaxSamples = 4;
+
FramebufferInfoTest()
- : manager_() {
+ : manager_(),
+ texture_manager_(kMaxTextureSize, kMaxCubemapSize),
+ renderbuffer_manager_(kMaxRenderbufferSize, kMaxSamples) {
}
~FramebufferInfoTest() {
manager_.Destroy(false);
+ texture_manager_.Destroy(false);
+ renderbuffer_manager_.Destroy(false);
}
protected:
@@ -107,12 +135,17 @@ class FramebufferInfoTest : public testing::Test {
scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
FramebufferManager manager_;
FramebufferManager::FramebufferInfo* info_;
+ TextureManager texture_manager_;
+ RenderbufferManager renderbuffer_manager_;
};
// GCC requires these declarations, but MSVC requires they not be present
#ifndef COMPILER_MSVC
const GLuint FramebufferInfoTest::kClient1Id;
const GLuint FramebufferInfoTest::kService1Id;
+const GLint FramebufferInfoTest::kMaxTextureSize;
+const GLint FramebufferInfoTest::kMaxCubemapSize;
+const GLint FramebufferInfoTest::kMaxRenderbufferSize;
#endif
TEST_F(FramebufferInfoTest, Basic) {
@@ -124,6 +157,9 @@ TEST_F(FramebufferInfoTest, Basic) {
EXPECT_TRUE(NULL == info_->GetAttachment(GL_DEPTH_STENCIL_ATTACHMENT));
EXPECT_FALSE(info_->HasDepthAttachment());
EXPECT_FALSE(info_->HasStencilAttachment());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT),
+ info_->IsPossiblyComplete());
+ EXPECT_TRUE(info_->IsCleared());
EXPECT_EQ(static_cast<GLenum>(0), info_->GetColorAttachmentFormat());
}
@@ -132,76 +168,123 @@ TEST_F(FramebufferInfoTest, AttachRenderbuffer) {
const GLuint kRenderbufferService1Id = 333;
const GLuint kRenderbufferClient2Id = 34;
const GLuint kRenderbufferService2Id = 334;
- const GLint kMaxRenderbufferSize = 128;
- const GLint kMaxSamples = 4;
+ const GLuint kRenderbufferClient3Id = 35;
+ const GLuint kRenderbufferService3Id = 335;
+ const GLuint kRenderbufferClient4Id = 36;
+ const GLuint kRenderbufferService4Id = 336;
const GLsizei kWidth1 = 16;
const GLsizei kHeight1 = 32;
- const GLenum kFormat1 = GL_STENCIL_INDEX8;
+ const GLenum kFormat1 = GL_RGBA4;
const GLsizei kSamples1 = 0;
- const GLsizei kWidth2 = 64;
- const GLsizei kHeight2 = 128;
- const GLenum kFormat2 = GL_STENCIL_INDEX;
+ const GLsizei kWidth2 = 16;
+ const GLsizei kHeight2 = 32;
+ const GLenum kFormat2 = GL_DEPTH_COMPONENT16;
const GLsizei kSamples2 = 0;
- const GLsizei kWidth3 = 75;
- const GLsizei kHeight3 = 123;
+ const GLsizei kWidth3 = 16;
+ const GLsizei kHeight3 = 32;
const GLenum kFormat3 = GL_STENCIL_INDEX8;
const GLsizei kSamples3 = 0;
+ const GLsizei kWidth4 = 16;
+ const GLsizei kHeight4 = 32;
+ const GLenum kFormat4 = GL_STENCIL_INDEX8;
+ const GLsizei kSamples4 = 0;
EXPECT_FALSE(info_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_FALSE(info_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
EXPECT_FALSE(info_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT));
EXPECT_FALSE(info_->HasUnclearedAttachment(GL_DEPTH_STENCIL_ATTACHMENT));
- EXPECT_FALSE(info_->IsNotComplete());
- RenderbufferManager rb_manager(kMaxRenderbufferSize, kMaxSamples);
- rb_manager.CreateRenderbufferInfo(
+ renderbuffer_manager_.CreateRenderbufferInfo(
kRenderbufferClient1Id, kRenderbufferService1Id);
RenderbufferManager::RenderbufferInfo* rb_info1 =
- rb_manager.GetRenderbufferInfo(kRenderbufferClient1Id);
+ renderbuffer_manager_.GetRenderbufferInfo(kRenderbufferClient1Id);
ASSERT_TRUE(rb_info1 != NULL);
// check adding one attachment
info_->AttachRenderbuffer(GL_COLOR_ATTACHMENT0, rb_info1);
- EXPECT_TRUE(info_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
+ EXPECT_FALSE(info_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_FALSE(info_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
- EXPECT_TRUE(info_->IsNotComplete());
EXPECT_EQ(static_cast<GLenum>(GL_RGBA4), info_->GetColorAttachmentFormat());
EXPECT_FALSE(info_->HasDepthAttachment());
EXPECT_FALSE(info_->HasStencilAttachment());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
+ info_->IsPossiblyComplete());
+ EXPECT_TRUE(info_->IsCleared());
- rb_info1->SetInfo(1, GL_RGB, 0, 0);
- EXPECT_EQ(static_cast<GLenum>(GL_RGB), info_->GetColorAttachmentFormat());
+ renderbuffer_manager_.SetInfo(
+ rb_info1, kSamples1, kFormat1, kWidth1, kHeight1);
+ EXPECT_EQ(static_cast<GLenum>(kFormat1), info_->GetColorAttachmentFormat());
EXPECT_FALSE(info_->HasDepthAttachment());
EXPECT_FALSE(info_->HasStencilAttachment());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ info_->IsPossiblyComplete());
+ EXPECT_FALSE(info_->IsCleared());
// check adding another
- info_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, rb_info1);
+ renderbuffer_manager_.CreateRenderbufferInfo(
+ kRenderbufferClient2Id, kRenderbufferService2Id);
+ RenderbufferManager::RenderbufferInfo* rb_info2 =
+ renderbuffer_manager_.GetRenderbufferInfo(kRenderbufferClient2Id);
+ ASSERT_TRUE(rb_info2 != NULL);
+ info_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, rb_info2);
EXPECT_TRUE(info_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
- EXPECT_TRUE(info_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
- EXPECT_TRUE(info_->IsNotComplete());
- EXPECT_EQ(static_cast<GLenum>(GL_RGB), info_->GetColorAttachmentFormat());
+ EXPECT_FALSE(info_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
+ EXPECT_EQ(static_cast<GLenum>(kFormat1), info_->GetColorAttachmentFormat());
EXPECT_TRUE(info_->HasDepthAttachment());
EXPECT_FALSE(info_->HasStencilAttachment());
+ // The attachment has a size of 0,0 so depending on the order of the map
+ // of attachments it could either get INCOMPLETE_ATTACHMENT because it's 0,0
+ // or INCOMPLETE_DIMENSIONS because it's not the same size as the other
+ // attachment.
+ GLenum status = info_->IsPossiblyComplete();
+ EXPECT_TRUE(
+ status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT ||
+ status == GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT);
+ EXPECT_FALSE(info_->IsCleared());
+
+ renderbuffer_manager_.SetInfo(
+ rb_info2, kSamples2, kFormat2, kWidth2, kHeight2);
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ info_->IsPossiblyComplete());
+ EXPECT_FALSE(info_->IsCleared());
+ EXPECT_TRUE(info_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
// check marking them as cleared.
- info_->MarkAttachedRenderbuffersAsCleared();
+ info_->MarkAttachmentsAsCleared(&renderbuffer_manager_, &texture_manager_);
EXPECT_FALSE(info_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_FALSE(info_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
- EXPECT_TRUE(info_->IsNotComplete());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ info_->IsPossiblyComplete());
+ EXPECT_TRUE(info_->IsCleared());
// Check adding one that is already cleared.
+ renderbuffer_manager_.CreateRenderbufferInfo(
+ kRenderbufferClient3Id, kRenderbufferService3Id);
+ RenderbufferManager::RenderbufferInfo* rb_info3 =
+ renderbuffer_manager_.GetRenderbufferInfo(kRenderbufferClient3Id);
+ ASSERT_TRUE(rb_info3 != NULL);
+ renderbuffer_manager_.SetInfo(
+ rb_info3, kSamples3, kFormat3, kWidth3, kHeight3);
+ renderbuffer_manager_.SetCleared(rb_info3);
+
info_->AttachRenderbuffer(GL_STENCIL_ATTACHMENT, rb_info1);
EXPECT_FALSE(info_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT));
- EXPECT_EQ(static_cast<GLenum>(GL_RGB), info_->GetColorAttachmentFormat());
+ EXPECT_EQ(static_cast<GLenum>(kFormat1), info_->GetColorAttachmentFormat());
EXPECT_TRUE(info_->HasDepthAttachment());
EXPECT_TRUE(info_->HasStencilAttachment());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ info_->IsPossiblyComplete());
+ EXPECT_TRUE(info_->IsCleared());
// Check marking the renderbuffer as unclared.
- rb_info1->SetInfo(kSamples1, kFormat1, kWidth1, kHeight1);
- EXPECT_FALSE(info_->IsNotComplete());
+ renderbuffer_manager_.SetInfo(
+ rb_info1, kSamples1, kFormat1, kWidth1, kHeight1);
EXPECT_EQ(static_cast<GLenum>(kFormat1), info_->GetColorAttachmentFormat());
EXPECT_TRUE(info_->HasDepthAttachment());
EXPECT_TRUE(info_->HasStencilAttachment());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ info_->IsPossiblyComplete());
+ EXPECT_FALSE(info_->IsCleared());
const FramebufferManager::FramebufferInfo::Attachment* attachment =
info_->GetAttachment(GL_COLOR_ATTACHMENT0);
@@ -215,38 +298,47 @@ TEST_F(FramebufferInfoTest, AttachRenderbuffer) {
EXPECT_TRUE(info_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT));
// Clear it.
- info_->MarkAttachedRenderbuffersAsCleared();
+ info_->MarkAttachmentsAsCleared(&renderbuffer_manager_, &texture_manager_);
EXPECT_FALSE(info_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT));
+ EXPECT_TRUE(info_->IsCleared());
// Check replacing an attachment
- rb_manager.CreateRenderbufferInfo(
- kRenderbufferClient2Id, kRenderbufferService2Id);
- RenderbufferManager::RenderbufferInfo* rb_info2 =
- rb_manager.GetRenderbufferInfo(kRenderbufferClient2Id);
- ASSERT_TRUE(rb_info2 != NULL);
- rb_info2->SetInfo(kSamples2, kFormat2, kWidth2, kHeight2);
-
- info_->AttachRenderbuffer(GL_STENCIL_ATTACHMENT, rb_info2);
+ renderbuffer_manager_.CreateRenderbufferInfo(
+ kRenderbufferClient4Id, kRenderbufferService4Id);
+ RenderbufferManager::RenderbufferInfo* rb_info4 =
+ renderbuffer_manager_.GetRenderbufferInfo(kRenderbufferClient4Id);
+ ASSERT_TRUE(rb_info4 != NULL);
+ renderbuffer_manager_.SetInfo(
+ rb_info4, kSamples4, kFormat4, kWidth4, kHeight4);
+
+ info_->AttachRenderbuffer(GL_STENCIL_ATTACHMENT, rb_info4);
EXPECT_TRUE(info_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT));
+ EXPECT_FALSE(info_->IsCleared());
attachment = info_->GetAttachment(GL_STENCIL_ATTACHMENT);
ASSERT_TRUE(attachment != NULL);
- EXPECT_EQ(kWidth2, attachment->width());
- EXPECT_EQ(kHeight2, attachment->height());
- EXPECT_EQ(kSamples2, attachment->samples());
- EXPECT_EQ(kFormat2, attachment->internal_format());
+ EXPECT_EQ(kWidth4, attachment->width());
+ EXPECT_EQ(kHeight4, attachment->height());
+ EXPECT_EQ(kSamples4, attachment->samples());
+ EXPECT_EQ(kFormat4, attachment->internal_format());
EXPECT_FALSE(attachment->cleared());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ info_->IsPossiblyComplete());
// Check changing an attachment.
- rb_info2->SetInfo(kSamples3, kFormat3, kWidth3, kHeight3);
+ renderbuffer_manager_.SetInfo(
+ rb_info4, kSamples4, kFormat4, kWidth4 + 1, kHeight4);
attachment = info_->GetAttachment(GL_STENCIL_ATTACHMENT);
ASSERT_TRUE(attachment != NULL);
- EXPECT_EQ(kWidth3, attachment->width());
- EXPECT_EQ(kHeight3, attachment->height());
- EXPECT_EQ(kSamples3, attachment->samples());
- EXPECT_EQ(kFormat3, attachment->internal_format());
+ EXPECT_EQ(kWidth4 + 1, attachment->width());
+ EXPECT_EQ(kHeight4, attachment->height());
+ EXPECT_EQ(kSamples4, attachment->samples());
+ EXPECT_EQ(kFormat4, attachment->internal_format());
EXPECT_FALSE(attachment->cleared());
+ EXPECT_FALSE(info_->IsCleared());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT),
+ info_->IsPossiblyComplete());
// Check removing it.
info_->AttachRenderbuffer(GL_STENCIL_ATTACHMENT, NULL);
@@ -255,7 +347,20 @@ TEST_F(FramebufferInfoTest, AttachRenderbuffer) {
EXPECT_TRUE(info_->HasDepthAttachment());
EXPECT_FALSE(info_->HasStencilAttachment());
- rb_manager.Destroy(false);
+ EXPECT_TRUE(info_->IsCleared());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ info_->IsPossiblyComplete());
+
+ // Remove depth, Set color to 0 size.
+ info_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, NULL);
+ renderbuffer_manager_.SetInfo(rb_info1, kSamples1, kFormat1, 0, 0);
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
+ info_->IsPossiblyComplete());
+
+ // Remove color.
+ info_->AttachRenderbuffer(GL_COLOR_ATTACHMENT0, NULL);
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT),
+ info_->IsPossiblyComplete());
}
TEST_F(FramebufferInfoTest, AttachTexture) {
@@ -263,7 +368,6 @@ TEST_F(FramebufferInfoTest, AttachTexture) {
const GLuint kTextureService1Id = 333;
const GLuint kTextureClient2Id = 34;
const GLuint kTextureService2Id = 334;
- const GLint kMaxTextureSize = 128;
const GLint kDepth = 1;
const GLint kBorder = 0;
const GLenum kType = GL_UNSIGNED_BYTE;
@@ -273,8 +377,8 @@ TEST_F(FramebufferInfoTest, AttachTexture) {
const GLenum kFormat1 = GL_RGBA;
const GLenum kTarget1 = GL_TEXTURE_2D;
const GLsizei kSamples1 = 0;
- const GLsizei kWidth2 = 64;
- const GLsizei kHeight2 = 128;
+ const GLsizei kWidth2 = 16;
+ const GLsizei kHeight2 = 32;
const GLint kLevel2 = 0;
const GLenum kFormat2 = GL_RGB;
const GLenum kTarget2 = GL_TEXTURE_2D;
@@ -288,27 +392,37 @@ TEST_F(FramebufferInfoTest, AttachTexture) {
EXPECT_FALSE(info_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
EXPECT_FALSE(info_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT));
EXPECT_FALSE(info_->HasUnclearedAttachment(GL_DEPTH_STENCIL_ATTACHMENT));
- EXPECT_FALSE(info_->IsNotComplete());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT),
+ info_->IsPossiblyComplete());
FeatureInfo feature_info;
- TextureManager tex_manager(kMaxTextureSize, kMaxTextureSize);
- tex_manager.CreateTextureInfo(
+ texture_manager_.CreateTextureInfo(
&feature_info, kTextureClient1Id, kTextureService1Id);
TextureManager::TextureInfo* tex_info1 =
- tex_manager.GetTextureInfo(kTextureClient1Id);
+ texture_manager_.GetTextureInfo(kTextureClient1Id);
ASSERT_TRUE(tex_info1 != NULL);
// check adding one attachment
info_->AttachTexture(GL_COLOR_ATTACHMENT0, tex_info1, kTarget1, kLevel1);
EXPECT_FALSE(info_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
- EXPECT_TRUE(info_->IsNotComplete());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
+ info_->IsPossiblyComplete());
+ EXPECT_TRUE(info_->IsCleared());
EXPECT_EQ(static_cast<GLenum>(0), info_->GetColorAttachmentFormat());
- tex_manager.SetInfoTarget(&feature_info, tex_info1, GL_TEXTURE_2D);
- tex_manager.SetLevelInfo(
+ texture_manager_.SetInfoTarget(&feature_info, tex_info1, GL_TEXTURE_2D);
+ texture_manager_.SetLevelInfo(
&feature_info, tex_info1, GL_TEXTURE_2D, kLevel1,
- kFormat1, kWidth1, kHeight1, kDepth, kBorder, kFormat1, kType);
- EXPECT_FALSE(info_->IsNotComplete());
+ kFormat1, kWidth1, kHeight1, kDepth, kBorder, kFormat1, kType, false);
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ info_->IsPossiblyComplete());
+ EXPECT_FALSE(info_->IsCleared());
+ texture_manager_.SetLevelInfo(
+ &feature_info, tex_info1, GL_TEXTURE_2D, kLevel1,
+ kFormat1, kWidth1, kHeight1, kDepth, kBorder, kFormat1, kType, true);
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ info_->IsPossiblyComplete());
+ EXPECT_TRUE(info_->IsCleared());
EXPECT_EQ(static_cast<GLenum>(kFormat1), info_->GetColorAttachmentFormat());
const FramebufferManager::FramebufferInfo::Attachment* attachment =
@@ -321,18 +435,21 @@ TEST_F(FramebufferInfoTest, AttachTexture) {
EXPECT_TRUE(attachment->cleared());
// Check replacing an attachment
- tex_manager.CreateTextureInfo(
+ texture_manager_.CreateTextureInfo(
&feature_info, kTextureClient2Id, kTextureService2Id);
TextureManager::TextureInfo* tex_info2 =
- tex_manager.GetTextureInfo(kTextureClient2Id);
+ texture_manager_.GetTextureInfo(kTextureClient2Id);
ASSERT_TRUE(tex_info2 != NULL);
- tex_manager.SetInfoTarget(&feature_info, tex_info2, GL_TEXTURE_2D);
- tex_manager.SetLevelInfo(
+ texture_manager_.SetInfoTarget(&feature_info, tex_info2, GL_TEXTURE_2D);
+ texture_manager_.SetLevelInfo(
&feature_info, tex_info2, GL_TEXTURE_2D, kLevel2,
- kFormat2, kWidth2, kHeight2, kDepth, kBorder, kFormat2, kType);
+ kFormat2, kWidth2, kHeight2, kDepth, kBorder, kFormat2, kType, true);
info_->AttachTexture(GL_COLOR_ATTACHMENT0, tex_info2, kTarget2, kLevel2);
EXPECT_EQ(static_cast<GLenum>(kFormat2), info_->GetColorAttachmentFormat());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ info_->IsPossiblyComplete());
+ EXPECT_TRUE(info_->IsCleared());
attachment = info_->GetAttachment(GL_COLOR_ATTACHMENT0);
ASSERT_TRUE(attachment != NULL);
@@ -343,24 +460,36 @@ TEST_F(FramebufferInfoTest, AttachTexture) {
EXPECT_TRUE(attachment->cleared());
// Check changing attachment
- tex_manager.SetLevelInfo(
+ texture_manager_.SetLevelInfo(
&feature_info, tex_info2, GL_TEXTURE_2D, kLevel3,
- kFormat3, kWidth3, kHeight3, kDepth, kBorder, kFormat3, kType);
+ kFormat3, kWidth3, kHeight3, kDepth, kBorder, kFormat3, kType, false);
attachment = info_->GetAttachment(GL_COLOR_ATTACHMENT0);
ASSERT_TRUE(attachment != NULL);
EXPECT_EQ(kWidth3, attachment->width());
EXPECT_EQ(kHeight3, attachment->height());
EXPECT_EQ(kSamples3, attachment->samples());
EXPECT_EQ(kFormat3, attachment->internal_format());
- EXPECT_TRUE(attachment->cleared());
+ EXPECT_FALSE(attachment->cleared());
EXPECT_EQ(static_cast<GLenum>(kFormat3), info_->GetColorAttachmentFormat());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ info_->IsPossiblyComplete());
+ EXPECT_FALSE(info_->IsCleared());
+
+ // Set to size 0
+ texture_manager_.SetLevelInfo(
+ &feature_info, tex_info2, GL_TEXTURE_2D, kLevel3,
+ kFormat3, 0, 0, kDepth, kBorder, kFormat3, kType, false);
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
+ info_->IsPossiblyComplete());
// Check removing it.
info_->AttachTexture(GL_COLOR_ATTACHMENT0, NULL, 0, 0);
EXPECT_TRUE(info_->GetAttachment(GL_COLOR_ATTACHMENT0) == NULL);
EXPECT_EQ(static_cast<GLenum>(0), info_->GetColorAttachmentFormat());
- tex_manager.Destroy(false);
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT),
+ info_->IsPossiblyComplete());
+ EXPECT_TRUE(info_->IsCleared());
}
} // namespace gles2
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 4b80834..e3b8722 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -353,9 +353,6 @@ class FrameBuffer {
// currently bound frame buffer.
void AttachRenderBuffer(GLenum target, RenderBuffer* render_buffer);
- // Clear the given attached buffers.
- void Clear(GLbitfield buffers);
-
// Destroy the frame buffer. This must be explicitly called before destroying
// this object.
void Destroy();
@@ -512,6 +509,7 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
virtual gfx::GLSurface* GetGLSurface() { return surface_.get(); }
virtual ContextGroup* GetContextGroup() { return group_.get(); }
+ virtual void SetGLError(GLenum error, const char* msg);
virtual void SetResizeCallback(Callback1<gfx::Size>::Type* callback);
#if defined(OS_MACOSX)
@@ -844,10 +842,29 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
error::Error ShaderSourceHelper(
GLuint client_id, const char* data, uint32 data_size);
- // Clears any uncleared render buffers attached to the given frame buffer.
- void ClearUnclearedRenderbuffers(
+ // Clear any textures used by the current program.
+ bool ClearUnclearedTextures();
+
+ // Clear any uncleared level in texture.
+ // Returns false if there was a generated GL error.
+ bool ClearTexture(TextureManager::TextureInfo* info);
+
+ // Clears any uncleared attachments attached to the given frame buffer.
+ // Returns false if there was a generated GL error.
+ void ClearUnclearedAttachments(
GLenum target, FramebufferManager::FramebufferInfo* info);
+ // overridden from GLES2Decoder
+ virtual bool ClearLevel(
+ unsigned service_id,
+ unsigned bind_target,
+ unsigned target,
+ int level,
+ unsigned format,
+ unsigned type,
+ int width,
+ int height);
+
// Restore all GL state that affects clearing.
void RestoreClearState();
@@ -855,8 +872,15 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
// Returns: true if glEnable/glDisable should actually be called.
bool SetCapabilityState(GLenum cap, bool enabled);
- // Check that the current frame buffer is complete. Generates error if not.
- bool CheckFramebufferComplete(const char* func_name);
+ // Check that the currently bound framebuffers are valid.
+ // Generates GL error if not.
+ bool CheckBoundFramebuffersValid(const char* func_name);
+
+ // Check if a framebuffer meets our requirements.
+ bool CheckFramebufferValid(
+ FramebufferManager::FramebufferInfo* framebuffer,
+ GLenum target,
+ const char* func_name);
// Checks if the current program exists and is valid. If not generates the
// appropriate GL error. Returns true if the current program is in a usable
@@ -1091,9 +1115,6 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
// this lets us peek at the error without losing it.
GLenum PeekGLError();
- // Sets our wrapper for the GLError.
- void SetGLError(GLenum error, const char* msg);
-
// Copies the real GL errors to the wrapper. This is so we can
// make sure there are no native GL errors before calling some GL function
// so that on return we know any error generated was for that specific
@@ -1186,6 +1207,20 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
return (info && !info->IsDeleted()) ? info : NULL;
}
+ RenderbufferManager::RenderbufferInfo* GetRenderbufferInfoForTarget(
+ GLenum target) {
+ RenderbufferManager::RenderbufferInfo* info = NULL;
+ switch (target) {
+ case GL_RENDERBUFFER:
+ info = bound_renderbuffer_;
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ return (info && !info->IsDeleted()) ? info : NULL;
+ }
+
// Validates the program and location for a glGetUniform call and returns
// a SizeResult setup to receive the result. Returns true if glGetUniform
// should be called.
@@ -1669,12 +1704,6 @@ void FrameBuffer::AttachRenderBuffer(GLenum target,
attach_id);
}
-void FrameBuffer::Clear(GLbitfield buffers) {
- ScopedGLErrorSuppressor suppressor(decoder_);
- ScopedFrameBufferBinder binder(decoder_, id_);
- glClear(buffers);
-}
-
void FrameBuffer::Destroy() {
if (id_ != 0) {
ScopedGLErrorSuppressor suppressor(decoder_);
@@ -2239,9 +2268,10 @@ bool GLES2DecoderImpl::MakeCurrent() {
}
void GLES2DecoderImpl::RestoreCurrentRenderbufferBindings() {
+ RenderbufferManager::RenderbufferInfo* renderbuffer =
+ GetRenderbufferInfoForTarget(GL_RENDERBUFFER);
glBindRenderbufferEXT(
- GL_RENDERBUFFER,
- bound_renderbuffer_ ? bound_renderbuffer_->service_id() : 0);
+ GL_RENDERBUFFER, renderbuffer ? renderbuffer->service_id() : 0);
}
static void RebindCurrentFramebuffer(
@@ -2290,19 +2320,59 @@ void GLES2DecoderImpl::RestoreCurrentTexture2DBindings() {
glActiveTexture(GL_TEXTURE0 + active_texture_unit_);
}
-bool GLES2DecoderImpl::CheckFramebufferComplete(const char* func_name) {
- if (bound_draw_framebuffer_ && bound_draw_framebuffer_->IsNotComplete()) {
- SetGLError(GL_INVALID_FRAMEBUFFER_OPERATION,
- (std::string(func_name) + " framebuffer incomplete").c_str());
+bool GLES2DecoderImpl::CheckFramebufferValid(
+ FramebufferManager::FramebufferInfo* framebuffer,
+ GLenum target, const char* func_name) {
+ if (!framebuffer || framebuffer->IsDeleted()) {
+ return true;
+ }
+
+ GLenum completeness = framebuffer->IsPossiblyComplete();
+ if (completeness != GL_FRAMEBUFFER_COMPLETE) {
+ SetGLError(
+ GL_INVALID_FRAMEBUFFER_OPERATION,
+ (std::string(func_name) + " framebuffer incomplete").c_str());
return false;
}
+
+ // Are all the attachments cleared?
+ if (renderbuffer_manager()->HaveUnclearedRenderbuffers() ||
+ texture_manager()->HaveUnclearedMips()) {
+ if (!framebuffer->IsCleared()) {
+ // Can we clear them?
+ if (glCheckFramebufferStatusEXT(target) != GL_FRAMEBUFFER_COMPLETE) {
+ SetGLError(
+ GL_INVALID_FRAMEBUFFER_OPERATION,
+ (std::string(func_name) +
+ " framebuffer incomplete (clear)").c_str());
+ return false;
+ }
+ ClearUnclearedAttachments(target, framebuffer);
+ }
+ }
+
+ // NOTE: At this point we don't know if the framebuffer is complete but
+ // we DO know that everything that needs to be cleared has been cleared.
return true;
}
+bool GLES2DecoderImpl::CheckBoundFramebuffersValid(const char* func_name) {
+ if (!feature_info_->feature_flags().chromium_framebuffer_multisample) {
+ return CheckFramebufferValid(
+ bound_draw_framebuffer_, GL_FRAMEBUFFER_EXT, func_name);
+ }
+ return CheckFramebufferValid(
+ bound_draw_framebuffer_, GL_DRAW_FRAMEBUFFER_EXT, func_name) &&
+ CheckFramebufferValid(
+ bound_read_framebuffer_, GL_READ_FRAMEBUFFER_EXT, func_name);
+}
+
gfx::Size GLES2DecoderImpl::GetBoundReadFrameBufferSize() {
- if (bound_read_framebuffer_ != 0) {
+ FramebufferManager::FramebufferInfo* framebuffer =
+ GetFramebufferInfoForTarget(GL_READ_FRAMEBUFFER);
+ if (framebuffer != NULL) {
const FramebufferManager::FramebufferInfo::Attachment* attachment =
- bound_read_framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0);
+ framebuffer->GetAttachment(GL_COLOR_ATTACHMENT0);
if (attachment) {
return gfx::Size(attachment->width(), attachment->height());
}
@@ -2315,8 +2385,10 @@ gfx::Size GLES2DecoderImpl::GetBoundReadFrameBufferSize() {
}
GLenum GLES2DecoderImpl::GetBoundReadFrameBufferInternalFormat() {
- if (bound_read_framebuffer_ != 0) {
- return bound_read_framebuffer_->GetColorAttachmentFormat();
+ FramebufferManager::FramebufferInfo* framebuffer =
+ GetFramebufferInfoForTarget(GL_READ_FRAMEBUFFER);
+ if (framebuffer != NULL) {
+ return framebuffer->GetColorAttachmentFormat();
} else if (offscreen_target_frame_buffer_.get()) {
return offscreen_target_color_format_;
} else {
@@ -2325,8 +2397,10 @@ GLenum GLES2DecoderImpl::GetBoundReadFrameBufferInternalFormat() {
}
GLenum GLES2DecoderImpl::GetBoundDrawFrameBufferInternalFormat() {
- if (bound_draw_framebuffer_ != 0) {
- return bound_draw_framebuffer_->GetColorAttachmentFormat();
+ FramebufferManager::FramebufferInfo* framebuffer =
+ GetFramebufferInfoForTarget(GL_DRAW_FRAMEBUFFER);
+ if (framebuffer != NULL) {
+ return framebuffer->GetColorAttachmentFormat();
} else if (offscreen_target_frame_buffer_.get()) {
return offscreen_target_color_format_;
} else {
@@ -2357,7 +2431,8 @@ void GLES2DecoderImpl::UpdateParentTextureInfo() {
1, // depth
0, // border
GL_RGBA,
- GL_UNSIGNED_BYTE);
+ GL_UNSIGNED_BYTE,
+ true);
parent_texture_manager->SetParameter(
feature_info_,
info,
@@ -2818,8 +2893,10 @@ bool GLES2DecoderImpl::BoundFramebufferHasColorAttachmentWithAlpha() {
}
bool GLES2DecoderImpl::BoundFramebufferHasDepthAttachment() {
- if (bound_draw_framebuffer_) {
- return bound_draw_framebuffer_->HasDepthAttachment();
+ FramebufferManager::FramebufferInfo* framebuffer =
+ GetFramebufferInfoForTarget(GL_DRAW_FRAMEBUFFER);
+ if (framebuffer) {
+ return framebuffer->HasDepthAttachment();
}
if (offscreen_target_frame_buffer_.get()) {
return offscreen_target_depth_format_ != 0;
@@ -2828,8 +2905,10 @@ bool GLES2DecoderImpl::BoundFramebufferHasDepthAttachment() {
}
bool GLES2DecoderImpl::BoundFramebufferHasStencilAttachment() {
- if (bound_draw_framebuffer_) {
- return bound_draw_framebuffer_->HasStencilAttachment();
+ FramebufferManager::FramebufferInfo* framebuffer =
+ GetFramebufferInfoForTarget(GL_DRAW_FRAMEBUFFER);
+ if (framebuffer) {
+ return framebuffer->HasStencilAttachment();
}
if (offscreen_target_frame_buffer_.get()) {
return offscreen_target_stencil_format_ != 0 ||
@@ -3236,10 +3315,12 @@ bool GLES2DecoderImpl::GetHelper(
// case GL_DRAW_FRAMEBUFFER_BINDING_EXT: (same as GL_FRAMEBUFFER_BINDING)
*num_written = 1;
if (params) {
- if (bound_draw_framebuffer_) {
+ FramebufferManager::FramebufferInfo* framebuffer =
+ GetFramebufferInfoForTarget(GL_DRAW_FRAMEBUFFER);
+ if (framebuffer) {
GLuint client_id = 0;
framebuffer_manager()->GetClientId(
- bound_draw_framebuffer_->service_id(), &client_id);
+ framebuffer->service_id(), &client_id);
*params = client_id;
} else {
*params = 0;
@@ -3249,10 +3330,12 @@ bool GLES2DecoderImpl::GetHelper(
case GL_READ_FRAMEBUFFER_BINDING:
*num_written = 1;
if (params) {
- if (bound_read_framebuffer_) {
+ FramebufferManager::FramebufferInfo* framebuffer =
+ GetFramebufferInfoForTarget(GL_READ_FRAMEBUFFER);
+ if (framebuffer) {
GLuint client_id = 0;
framebuffer_manager()->GetClientId(
- bound_read_framebuffer_->service_id(), &client_id);
+ framebuffer->service_id(), &client_id);
*params = client_id;
} else {
*params = 0;
@@ -3262,10 +3345,12 @@ bool GLES2DecoderImpl::GetHelper(
case GL_RENDERBUFFER_BINDING:
*num_written = 1;
if (params) {
- if (bound_renderbuffer_) {
+ RenderbufferManager::RenderbufferInfo* renderbuffer =
+ GetRenderbufferInfoForTarget(GL_RENDERBUFFER);
+ if (renderbuffer) {
GLuint client_id = 0;
renderbuffer_manager()->GetClientId(
- bound_renderbuffer_->service_id(), &client_id);
+ renderbuffer->service_id(), &client_id);
*params = client_id;
} else {
*params = 0;
@@ -3583,7 +3668,7 @@ error::Error GLES2DecoderImpl::HandleRegisterSharedIdsCHROMIUM(
}
void GLES2DecoderImpl::DoClear(GLbitfield mask) {
- if (CheckFramebufferComplete("glClear")) {
+ if (CheckBoundFramebuffersValid("glClear")) {
ApplyDirtyState();
glClear(mask);
}
@@ -3616,12 +3701,6 @@ void GLES2DecoderImpl::DoFramebufferRenderbuffer(
GLenum error = PeekGLError();
if (error == GL_NO_ERROR) {
framebuffer_info->AttachRenderbuffer(attachment, info);
- if (service_id == 0 ||
- glCheckFramebufferStatusEXT(target) == GL_FRAMEBUFFER_COMPLETE) {
- if (info) {
- ClearUnclearedRenderbuffers(target, framebuffer_info);
- }
- }
}
if (framebuffer_info == bound_draw_framebuffer_) {
state_dirty_ = true;
@@ -3712,20 +3791,24 @@ void GLES2DecoderImpl::DoStencilMaskSeparate(GLenum face, GLuint mask) {
state_dirty_ = true;
}
-// NOTE: There's an assumption here that Texture attachments
-// are cleared because they are textures so we only need to clear
-// the renderbuffers.
-void GLES2DecoderImpl::ClearUnclearedRenderbuffers(
+// Assumes framebuffer is complete.
+void GLES2DecoderImpl::ClearUnclearedAttachments(
GLenum target, FramebufferManager::FramebufferInfo* info) {
+ DCHECK(!info->IsDeleted());
if (target == GL_READ_FRAMEBUFFER_EXT) {
- // TODO(gman): bind this to the DRAW point, clear then bind back to READ
+ // bind this to the DRAW point, clear then bind back to READ
+ // TODO(gman): I don't think there is any guarantee that an FBO that
+ // is complete on the READ attachment will be complete as a DRAW
+ // attachment.
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, info->service_id());
}
GLbitfield clear_bits = 0;
if (info->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)) {
glClearColor(
- 0, 0, 0,
+ 0.0f, 0.0f, 0.0f,
(GLES2Util::GetChannelsForFormat(
- info->GetColorAttachmentFormat()) & 0x0008) != 0 ? 0 : 1);
+ info->GetColorAttachmentFormat()) & 0x0008) != 0 ? 0.0f : 1.0f);
glColorMask(true, true, true, true);
clear_bits |= GL_COLOR_BUFFER_BIT;
}
@@ -3747,12 +3830,16 @@ void GLES2DecoderImpl::ClearUnclearedRenderbuffers(
glDisable(GL_SCISSOR_TEST);
glClear(clear_bits);
- info->MarkAttachedRenderbuffersAsCleared();
+ info->MarkAttachmentsAsCleared(renderbuffer_manager(), texture_manager());
RestoreClearState();
if (target == GL_READ_FRAMEBUFFER_EXT) {
- // TODO(gman): rebind draw.
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, info->service_id());
+ FramebufferManager::FramebufferInfo*framebuffer =
+ GetFramebufferInfoForTarget(GL_READ_FRAMEBUFFER);
+ glBindFramebufferEXT(
+ GL_DRAW_FRAMEBUFFER_EXT, framebuffer ? framebuffer->service_id() : 0);
}
}
@@ -3767,11 +3854,15 @@ void GLES2DecoderImpl::RestoreClearState() {
}
GLenum GLES2DecoderImpl::DoCheckFramebufferStatus(GLenum target) {
- FramebufferManager::FramebufferInfo* info =
+ FramebufferManager::FramebufferInfo* framebuffer =
GetFramebufferInfoForTarget(target);
- if (!info) {
+ if (!framebuffer) {
return GL_FRAMEBUFFER_COMPLETE;
}
+ GLenum completeness = framebuffer->IsPossiblyComplete();
+ if (completeness != GL_FRAMEBUFFER_COMPLETE) {
+ return completeness;
+ }
return glCheckFramebufferStatusEXT(target);
}
@@ -3796,15 +3887,19 @@ void GLES2DecoderImpl::DoFramebufferTexture2D(
}
service_id = info->service_id();
}
+
+ if (!texture_manager()->ValidForTarget(
+ feature_info_, textarget, level, 0, 0, 1)) {
+ SetGLError(GL_INVALID_VALUE,
+ "glFramebufferTexture2D: level out of range");
+ return;
+ }
+
CopyRealGLErrorsToWrapper();
glFramebufferTexture2DEXT(target, attachment, textarget, service_id, level);
GLenum error = PeekGLError();
if (error == GL_NO_ERROR) {
framebuffer_info->AttachTexture(attachment, info, textarget, level);
- if (service_id != 0 &&
- glCheckFramebufferStatusEXT(target) == GL_FRAMEBUFFER_COMPLETE) {
- ClearUnclearedRenderbuffers(target, framebuffer_info);
- }
}
if (framebuffer_info == bound_draw_framebuffer_) {
state_dirty_ = true;
@@ -3844,20 +3939,22 @@ void GLES2DecoderImpl::DoGetFramebufferAttachmentParameteriv(
void GLES2DecoderImpl::DoGetRenderbufferParameteriv(
GLenum target, GLenum pname, GLint* params) {
- if (!bound_renderbuffer_) {
+ RenderbufferManager::RenderbufferInfo* renderbuffer =
+ GetRenderbufferInfoForTarget(GL_RENDERBUFFER);
+ if (!renderbuffer) {
SetGLError(GL_INVALID_OPERATION,
"glGetRenderbufferParameteriv: no renderbuffer bound");
return;
}
switch (pname) {
case GL_RENDERBUFFER_INTERNAL_FORMAT:
- *params = bound_renderbuffer_->internal_format();
+ *params = renderbuffer->internal_format();
break;
case GL_RENDERBUFFER_WIDTH:
- *params = bound_renderbuffer_->width();
+ *params = renderbuffer->width();
break;
case GL_RENDERBUFFER_HEIGHT:
- *params = bound_renderbuffer_->height();
+ *params = renderbuffer->height();
break;
default:
glGetRenderbufferParameterivEXT(target, pname, params);
@@ -3891,6 +3988,14 @@ void GLES2DecoderImpl::DoRenderbufferStorageMultisample(
return;
}
+ RenderbufferManager::RenderbufferInfo* renderbuffer =
+ GetRenderbufferInfoForTarget(GL_RENDERBUFFER);
+ if (!renderbuffer) {
+ SetGLError(GL_INVALID_OPERATION,
+ "glGetRenderbufferStorageMultisample: no renderbuffer bound");
+ return;
+ }
+
if (samples > renderbuffer_manager()->max_samples()) {
SetGLError(GL_INVALID_VALUE,
"glGetRenderbufferStorageMultisample: samples too large");
@@ -3930,13 +4035,16 @@ void GLES2DecoderImpl::DoRenderbufferStorageMultisample(
}
GLenum error = PeekGLError();
if (error == GL_NO_ERROR) {
- bound_renderbuffer_->SetInfo(samples, internalformat, width, height);
+ renderbuffer_manager()->SetInfo(
+ renderbuffer, samples, internalformat, width, height);
}
}
void GLES2DecoderImpl::DoRenderbufferStorage(
GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
- if (!bound_renderbuffer_) {
+ RenderbufferManager::RenderbufferInfo* renderbuffer =
+ GetRenderbufferInfoForTarget(GL_RENDERBUFFER);
+ if (!renderbuffer) {
SetGLError(GL_INVALID_OPERATION,
"glGetRenderbufferStorage: no renderbuffer bound");
return;
@@ -3969,7 +4077,8 @@ void GLES2DecoderImpl::DoRenderbufferStorage(
glRenderbufferStorageEXT(target, impl_format, width, height);
GLenum error = PeekGLError();
if (error == GL_NO_ERROR) {
- bound_renderbuffer_->SetInfo(0, internalformat, width, height);
+ renderbuffer_manager()->SetInfo(
+ renderbuffer, 0, internalformat, width, height);
}
}
@@ -4389,6 +4498,38 @@ void GLES2DecoderImpl::RestoreStateForNonRenderableTextures() {
glActiveTexture(GL_TEXTURE0 + active_texture_unit_);
}
+bool GLES2DecoderImpl::ClearUnclearedTextures() {
+ // Only check if there are some uncleared textures.
+ if (!texture_manager()->HaveUnsafeTextures()) {
+ return true;
+ }
+
+ // 1: Check all textures we are about to render with.
+ if (current_program_) {
+ const ProgramManager::ProgramInfo::SamplerIndices& sampler_indices =
+ current_program_->sampler_indices();
+ for (size_t ii = 0; ii < sampler_indices.size(); ++ii) {
+ const ProgramManager::ProgramInfo::UniformInfo* uniform_info =
+ current_program_->GetUniformInfo(sampler_indices[ii]);
+ DCHECK(uniform_info);
+ for (size_t jj = 0; jj < uniform_info->texture_units.size(); ++jj) {
+ GLuint texture_unit_index = uniform_info->texture_units[jj];
+ if (texture_unit_index < group_->max_texture_units()) {
+ TextureUnit& texture_unit = texture_units_[texture_unit_index];
+ TextureManager::TextureInfo* texture_info =
+ texture_unit.GetInfoForSamplerType(uniform_info->type);
+ if (texture_info && !texture_info->SafeToRenderFrom()) {
+ if (!texture_manager()->ClearRenderableLevels(this, texture_info)) {
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
bool GLES2DecoderImpl::IsDrawValid(GLuint max_vertex_accessed) {
// NOTE: We specifically do not check current_program->IsValid() because
// it could never be invalid since glUseProgram would have failed. While
@@ -4623,7 +4764,7 @@ error::Error GLES2DecoderImpl::HandleDrawArrays(
SetGLError(GL_INVALID_VALUE, "glDrawArrays: count < 0");
return error::kNoError;
}
- if (!CheckFramebufferComplete("glDrawArrays")) {
+ if (!CheckBoundFramebuffersValid("glDrawArrays")) {
return error::kNoError;
}
// We have to check this here because the prototype for glDrawArrays
@@ -4639,6 +4780,10 @@ error::Error GLES2DecoderImpl::HandleDrawArrays(
GLuint max_vertex_accessed = first + count - 1;
if (IsDrawValid(max_vertex_accessed)) {
+ if (!ClearUnclearedTextures()) {
+ SetGLError(GL_INVALID_VALUE, "glDrawArrays: out of memory");
+ return error::kNoError;
+ }
bool simulated_attrib_0 = false;
if (!SimulateAttrib0(max_vertex_accessed, &simulated_attrib_0)) {
return error::kNoError;
@@ -4696,7 +4841,7 @@ error::Error GLES2DecoderImpl::HandleDrawElements(
return error::kNoError;
}
- if (!CheckFramebufferComplete("glDrawElements")) {
+ if (!CheckBoundFramebuffersValid("glDrawElements")) {
return error::kNoError;
}
@@ -4713,6 +4858,10 @@ error::Error GLES2DecoderImpl::HandleDrawElements(
}
if (IsDrawValid(max_vertex_accessed)) {
+ if (!ClearUnclearedTextures()) {
+ SetGLError(GL_INVALID_VALUE, "glDrawElements: out of memory");
+ return error::kNoError;
+ }
bool simulated_attrib_0 = false;
if (!SimulateAttrib0(max_vertex_accessed, &simulated_attrib_0)) {
return error::kNoError;
@@ -5395,6 +5544,10 @@ error::Error GLES2DecoderImpl::HandleReadPixels(
return error::kNoError;
}
+ if (!CheckBoundFramebuffersValid("glReadPixels")) {
+ return error::kNoError;
+ }
+
if (x < 0 || y < 0 || max_x > max_size.width() || max_y > max_size.height()) {
// The user requested an out of range area. Get the results 1 line
// at a time.
@@ -5810,6 +5963,31 @@ void GLES2DecoderImpl::DoBufferSubData(
glBufferSubData(target, offset, size, data);
}
+bool GLES2DecoderImpl::ClearLevel(
+ unsigned service_id,
+ unsigned bind_target,
+ unsigned target,
+ int level,
+ unsigned format,
+ unsigned type,
+ int width,
+ int height) {
+ // Assumes the size has already been checked.
+ uint32 pixels_size = 0;
+ if (!GLES2Util::ComputeImageDataSize(
+ width, height, format, type, unpack_alignment_, &pixels_size)) {
+ return false;
+ }
+ scoped_array<char> zero(new char[pixels_size]);
+ memset(zero.get(), 0, pixels_size);
+ glBindTexture(bind_target, service_id);
+ WrappedTexImage2D(
+ target, level, format, width, height, 0, format, type, zero.get());
+ TextureManager::TextureInfo* info = GetTextureInfoForTarget(bind_target);
+ glBindTexture(bind_target, info ? info->service_id() : 0);
+ return true;
+}
+
error::Error GLES2DecoderImpl::DoCompressedTexImage2D(
GLenum target,
GLint level,
@@ -5857,7 +6035,8 @@ error::Error GLES2DecoderImpl::DoCompressedTexImage2D(
if (error == GL_NO_ERROR) {
texture_manager()->SetLevelInfo(
feature_info_,
- info, target, level, internal_format, width, height, 1, border, 0, 0);
+ info, target, level, internal_format, width, height, 1, border, 0, 0,
+ true);
}
return error::kNoError;
}
@@ -6033,13 +6212,6 @@ error::Error GLES2DecoderImpl::DoTexImage2D(
return error::kNoError;
}
- scoped_array<int8> zero;
- if (!pixels) {
- zero.reset(new int8[pixels_size]);
- memset(zero.get(), 0, pixels_size);
- pixels = zero.get();
- }
-
if (info->IsAttachedToFramebuffer()) {
state_dirty_ = true;
}
@@ -6056,8 +6228,10 @@ error::Error GLES2DecoderImpl::DoTexImage2D(
pixels);
GLenum error = PeekGLError();
if (error == GL_NO_ERROR) {
- texture_manager()->SetLevelInfo(feature_info_, info,
- target, level, internal_format, width, height, 1, border, format, type);
+ texture_manager()->SetLevelInfo(
+ feature_info_, info,
+ target, level, internal_format, width, height, 1, border, format, type,
+ pixels != NULL);
tex_image_2d_failed_ = false;
}
return error::kNoError;
@@ -6157,6 +6331,10 @@ void GLES2DecoderImpl::DoCompressedTexSubImage2D(
"glCompressdTexSubImage2D: bad dimensions.");
return;
}
+ // Note: There is no need to deal with texture cleared tracking here
+ // because the validation above means you can only get here if the level
+ // is already a matching compressed format and in that case
+ // CompressedTexImage2D already cleared the texture.
glCompressedTexSubImage2D(
target, level, xoffset, yoffset, width, height, format, image_size, data);
}
@@ -6178,7 +6356,6 @@ static void Clip(
*out_range = range;
}
-
void GLES2DecoderImpl::DoCopyTexImage2D(
GLenum target,
GLint level,
@@ -6232,17 +6409,12 @@ void GLES2DecoderImpl::DoCopyTexImage2D(
copyWidth != width ||
copyHeight != height) {
// some part was clipped so clear the texture.
- uint32 pixels_size = 0;
- if (!GLES2Util::ComputeImageDataSize(
- width, height, internal_format, GL_UNSIGNED_BYTE,
- unpack_alignment_, &pixels_size)) {
- SetGLError(GL_INVALID_VALUE, "glCopyTexImage2D: dimensions too large");
+ if (!ClearLevel(
+ info->service_id(), info->target(),
+ target, level, internal_format, GL_UNSIGNED_BYTE, width, height)) {
+ SetGLError(GL_OUT_OF_MEMORY, "glCopyTexImage2D: dimensions too big");
return;
}
- scoped_array<char> zero(new char[pixels_size]);
- memset(zero.get(), 0, pixels_size);
- glTexImage2D(target, level, internal_format, width, height, 0,
- internal_format, GL_UNSIGNED_BYTE, zero.get());
if (copyHeight > 0 && copyWidth > 0) {
GLint dx = copyX - x;
GLint dy = copyY - y;
@@ -6260,7 +6432,7 @@ void GLES2DecoderImpl::DoCopyTexImage2D(
if (error == GL_NO_ERROR) {
texture_manager()->SetLevelInfo(
feature_info_, info, target, level, internal_format, width, height, 1,
- border, internal_format, GL_UNSIGNED_BYTE);
+ border, internal_format, GL_UNSIGNED_BYTE, true);
}
}
@@ -6308,11 +6480,17 @@ void GLES2DecoderImpl::DoCopyTexSubImage2D(
GLint copyHeight = 0;
Clip(x, width, size.width(), &copyX, &copyWidth);
Clip(y, height, size.height(), &copyY, &copyHeight);
+
+ if (!texture_manager()->ClearTextureLevel(this, info, target, level)) {
+ SetGLError(GL_OUT_OF_MEMORY, "glCopyTexSubImage2D: dimensions too big");
+ return;
+ }
+
if (copyX != x ||
copyY != y ||
copyWidth != width ||
copyHeight != height) {
- // some part was clipped so clear the texture.
+ // some part was clipped so clear the sub rect.
uint32 pixels_size = 0;
if (!GLES2Util::ComputeImageDataSize(
width, height, format, type, unpack_alignment_, &pixels_size)) {
@@ -6325,6 +6503,7 @@ void GLES2DecoderImpl::DoCopyTexSubImage2D(
target, level, xoffset, yoffset, width, height,
format, type, zero.get());
}
+
if (copyHeight > 0 && copyWidth > 0) {
GLint dx = copyX - x;
GLint dy = copyY - y;
@@ -6389,9 +6568,14 @@ void GLES2DecoderImpl::DoTexSubImage2D(
// same as internal_foramt. If that changes we'll need to look them up.
WrappedTexImage2D(
target, level, format, width, height, 0, format, type, data);
+ texture_manager()->SetLevelCleared(info, target, level);
return;
}
}
+ if (!texture_manager()->ClearTextureLevel(this, info, target, level)) {
+ SetGLError(GL_OUT_OF_MEMORY, "glTexSubImage2D: dimensions too big");
+ return;
+ }
glTexSubImage2D(
target, level, xoffset, yoffset, width, height, format, type, data);
}
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h
index 118c27d..6398bff 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.h
@@ -122,6 +122,18 @@ class GLES2Decoder : public CommonDecoder {
// Provides detail about a lost context if one occurred.
virtual error::ContextLostReason GetContextLostReason() = 0;
+ // Clears a level of a texture
+ // Returns false if a GL error should be generated.
+ virtual bool ClearLevel(
+ unsigned service_id,
+ unsigned bind_target,
+ unsigned target,
+ int level,
+ unsigned format,
+ unsigned type,
+ int width,
+ int height) = 0;
+
protected:
GLES2Decoder();
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
index 6eb313d..7cdd56c 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
@@ -56,6 +56,15 @@ class MockGLES2Decoder : public GLES2Decoder {
uint32* service_texture_id));
MOCK_METHOD0(GetContextLostReason, error::ContextLostReason());
MOCK_CONST_METHOD1(GetCommandName, const char*(unsigned int command_id));
+ MOCK_METHOD8(ClearLevel, bool(
+ unsigned service_id,
+ unsigned bind_target,
+ unsigned target,
+ int level,
+ unsigned format,
+ unsigned type,
+ int width,
+ int height));
DISALLOW_COPY_AND_ASSIGN(MockGLES2Decoder);
};
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index 2a1e663..2790dab 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -56,51 +56,6 @@ class GLES2DecoderWithShaderTest : public GLES2DecoderWithShaderTestBase {
GLES2DecoderWithShaderTest()
: GLES2DecoderWithShaderTestBase() {
}
-
-
- void AddExpectationsForSimulatedAttrib0WithError(
- GLsizei num_vertices, GLuint buffer_id, GLenum error) {
- if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) {
- return;
- }
-
- EXPECT_CALL(*gl_, GetError())
- .WillOnce(Return(GL_NO_ERROR))
- .WillOnce(Return(error))
- .RetiresOnSaturation();
- EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, kServiceAttrib0BufferId))
- .Times(1)
- .RetiresOnSaturation();
- EXPECT_CALL(*gl_, BufferData(GL_ARRAY_BUFFER,
- num_vertices * sizeof(GLfloat) * 4,
- _, GL_DYNAMIC_DRAW))
- .Times(1)
- .RetiresOnSaturation();
- if (error == GL_NO_ERROR) {
- EXPECT_CALL(*gl_, BufferSubData(
- GL_ARRAY_BUFFER, 0, num_vertices * sizeof(GLfloat) * 4, _))
- .Times(1)
- .RetiresOnSaturation();
- EXPECT_CALL(*gl_, VertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL))
- .Times(1)
- .RetiresOnSaturation();
- EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, 0))
- .Times(1)
- .RetiresOnSaturation();
- EXPECT_CALL(*gl_, VertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL))
- .Times(1)
- .RetiresOnSaturation();
- EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, buffer_id))
- .Times(1)
- .RetiresOnSaturation();
- }
- }
-
- void AddExpectationsForSimulatedAttrib0(
- GLsizei num_vertices, GLuint buffer_id) {
- AddExpectationsForSimulatedAttrib0WithError(
- num_vertices, buffer_id, GL_NO_ERROR);
- }
};
class GLES2DecoderRGBBackbufferTest : public GLES2DecoderWithShaderTest {
@@ -190,7 +145,7 @@ TEST_F(GLES2DecoderWithShaderTest, DrawArraysBadTextureUsesBlack) {
// This is an NPOT texture. As the default filtering requires mips
// this should trigger replacing with black textures before rendering.
DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
- 0, 0);
+ kSharedMemoryId, kSharedMemoryOffset);
AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
{
InSequence sequence;
@@ -1455,12 +1410,6 @@ TEST_F(GLES2DecoderTest, GetFramebufferAttachmentParameterivWithRenderbuffer) {
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
- SetupExpectationsForFramebufferAttachment(
- GL_COLOR_BUFFER_BIT, // clear bits
- 0, 0, 0, 0, // color
- 0, // stencil
- 1.0f, // depth
- false); // scissor test
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.WillOnce(Return(GL_NO_ERROR))
@@ -1511,12 +1460,6 @@ TEST_F(GLES2DecoderTest, GetFramebufferAttachmentParameterivWithTexture) {
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
- SetupExpectationsForFramebufferAttachment(
- 0, // clear bits
- 0, 0, 0, 0, // color
- 0, // stencil
- 1.0f, // depth
- false); // scissor test
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.WillOnce(Return(GL_NO_ERROR))
@@ -1674,32 +1617,15 @@ void GLES2DecoderTest::CheckReadPixelsOutOfRange(
// access
if (init) {
DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
- DoTexImage2D(GL_TEXTURE_2D, 0, kFormat, kWidth, kHeight, 0,
- kFormat, GL_UNSIGNED_BYTE, 0, 0);
- DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
- kServiceFramebufferId);
- EXPECT_CALL(*gl_, GetError())
- .WillOnce(Return(GL_NO_ERROR))
- .RetiresOnSaturation();
- EXPECT_CALL(*gl_, FramebufferTexture2DEXT(
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, kFormat, kWidth, kHeight, 0,
+ kFormat, GL_UNSIGNED_BYTE, kSharedMemoryId,
+ kSharedMemoryOffset);
+ DoBindFramebuffer(
+ GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
+ DoFramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- kServiceTextureId, 0))
- .Times(1)
- .RetiresOnSaturation();
- EXPECT_CALL(*gl_, GetError())
- .WillOnce(Return(GL_NO_ERROR))
- .RetiresOnSaturation();
- SetupExpectationsForFramebufferAttachment(
- 0, // clear bits
- 0, 0, 0, 0, // color
- 0, // stencil
- 1.0f, // depth
- false); // scissor test
- FramebufferTexture2D fbtex_cmd;
- fbtex_cmd.Init(
- GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, client_texture_id_,
- 0);
- EXPECT_EQ(error::kNoError, ExecuteCmd(fbtex_cmd));
+ client_texture_id_, kServiceTextureId, 0, GL_NO_ERROR);
}
ReadPixelsEmulator emu(
@@ -2559,7 +2485,7 @@ TEST_F(GLES2DecoderTest, TexSubImage2DValidArgs) {
DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
DoTexImage2D(
GL_TEXTURE_2D, 1, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
- 0, 0);
+ kSharedMemoryId, kSharedMemoryOffset);
EXPECT_CALL(*gl_, TexSubImage2D(
GL_TEXTURE_2D, 1, 1, 0, kWidth - 1, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
shared_memory_address_))
@@ -2640,7 +2566,7 @@ TEST_F(GLES2DecoderTest, CopyTexSubImage2DValidArgs) {
DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
DoTexImage2D(
GL_TEXTURE_2D, 1, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
- 0, 0);
+ kSharedMemoryId, kSharedMemoryOffset);
EXPECT_CALL(*gl_, CopyTexSubImage2D(
GL_TEXTURE_2D, 1, 0, 0, 0, 0, kWidth, kHeight))
.Times(1)
@@ -2701,9 +2627,6 @@ TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearColor) {
EXPECT_CALL(*gl_, ClearColor(0.1f, 0.2f, 0.3f, 0.4f))
.Times(1)
.RetiresOnSaturation();
-// EXPECT_CALL(*gl_, ColorMask(0, 1, 0, 1))
-// .Times(0)
-// .RetiresOnSaturation();
EXPECT_CALL(*gl_, Enable(GL_SCISSOR_TEST))
.Times(1)
.RetiresOnSaturation();
@@ -2718,12 +2641,6 @@ TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearColor) {
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
- SetupExpectationsForFramebufferAttachment(
- GL_COLOR_BUFFER_BIT, // clear bits
- 0.1f, 0.2f, 0.3f, 0.4f, // color
- 0, // stencil
- 1.0f, // depth
- true); // scissor test
EXPECT_EQ(error::kNoError, ExecuteCmd(color_cmd));
EXPECT_EQ(error::kNoError, ExecuteCmd(color_mask_cmd));
EXPECT_EQ(error::kNoError, ExecuteCmd(enable_cmd));
@@ -2745,9 +2662,6 @@ TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearDepth) {
EXPECT_CALL(*gl_, ClearDepth(0.5f))
.Times(1)
.RetiresOnSaturation();
-// EXPECT_CALL(*gl_, DepthMask(0))
-// .Times(1)
-// .RetiresOnSaturation();
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
@@ -2759,12 +2673,6 @@ TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearDepth) {
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
- SetupExpectationsForFramebufferAttachment(
- GL_DEPTH_BUFFER_BIT, // clear bits
- 0, 0, 0, 0, // color
- 0, // stencil
- 0.5f, // depth
- false); // scissor test
EXPECT_EQ(error::kNoError, ExecuteCmd(depth_cmd));
EXPECT_EQ(error::kNoError, ExecuteCmd(depth_mask_cmd));
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
@@ -2785,9 +2693,6 @@ TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearStencil) {
EXPECT_CALL(*gl_, ClearStencil(123))
.Times(1)
.RetiresOnSaturation();
-// EXPECT_CALL(*gl_, StencilMaskSeparate(GL_BACK, 0x1234u))
-// .Times(1)
-// .RetiresOnSaturation();
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
@@ -2799,12 +2704,6 @@ TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearStencil) {
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
- SetupExpectationsForFramebufferAttachment(
- GL_STENCIL_BUFFER_BIT, // clear bits
- 0, 0, 0, 0, // color
- 123, // stencil
- 1.0f, // depth
- false); // scissor test
EXPECT_EQ(error::kNoError, ExecuteCmd(stencil_cmd));
EXPECT_EQ(error::kNoError, ExecuteCmd(stencil_mask_separate_cmd));
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
@@ -2885,12 +2784,6 @@ TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearDepthStencil) {
kServiceRenderbufferId))
.Times(1)
.RetiresOnSaturation();
- SetupExpectationsForFramebufferAttachment(
- GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, // clear bits
- 0, 0, 0, 0, // color
- 123, // stencil
- 0.5f, // depth
- false); // scissor test
EXPECT_EQ(error::kNoError, ExecuteCmd(depth_cmd));
EXPECT_EQ(error::kNoError, ExecuteCmd(stencil_cmd));
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
@@ -3230,15 +3123,20 @@ TEST_F(GLES2DecoderRGBBackbufferTest, RGBBackbufferColorMaskFBO) {
EXPECT_EQ(GL_NO_ERROR, GetGLError());
// Setup Frame buffer.
- DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
- kServiceFramebufferId);
- EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(_, _, _, _))
- .Times(0);
- FramebufferRenderbuffer fbrb_cmd;
- fbrb_cmd.Init(
- GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
- client_renderbuffer_id_);
- EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ // needs to be 1x1 or else it's not renderable.
+ const GLsizei kWidth = 1;
+ const GLsizei kHeight = 1;
+ const GLenum kFormat = GL_RGB;
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ // Pass some data so the texture will be marked as cleared.
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, kFormat, kWidth, kHeight, 0,
+ kFormat, GL_UNSIGNED_BYTE, kSharedMemoryId, kSharedMemoryOffset);
+ DoBindFramebuffer(
+ GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
+ DoFramebufferTexture2D(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ client_texture_id_, kServiceTextureId, 0, GL_NO_ERROR);
// This time state needs to be set.
SetupExpectationsForApplyingDirtyState(
@@ -3825,12 +3723,6 @@ TEST_F(GLES2DecoderManualInitTest, PackedDepthStencilRenderbufferDepth) {
kServiceRenderbufferId))
.Times(1)
.RetiresOnSaturation();
- SetupExpectationsForFramebufferAttachment(
- GL_DEPTH_BUFFER_BIT, // clear bits
- 0, 0, 0, 0, // color
- 0, // stencil
- 1.0f, // depth
- false); // scissor test
FramebufferRenderbuffer fbrb_cmd;
fbrb_cmd.Init(
GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
@@ -3902,12 +3794,6 @@ TEST_F(GLES2DecoderManualInitTest, PackedDepthStencilRenderbufferStencil) {
kServiceRenderbufferId))
.Times(1)
.RetiresOnSaturation();
- SetupExpectationsForFramebufferAttachment(
- GL_STENCIL_BUFFER_BIT, // clear bits
- 0, 0, 0, 0, // color
- 0, // stencil
- 1.0f, // depth
- false); // scissor test
FramebufferRenderbuffer fbrb_cmd;
fbrb_cmd.Init(
GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
@@ -4078,17 +3964,21 @@ TEST_F(GLES2DecoderTest, TexImage2DRedefinitionSucceeds) {
EXPECT_CALL(*gl_, GetError())
.WillRepeatedly(Return(GL_NO_ERROR));
for (int ii = 0; ii < 2; ++ii) {
+ TexImage2D cmd;
if (ii == 0) {
EXPECT_CALL(*gl_, TexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, _))
.Times(1)
.RetiresOnSaturation();
+ cmd.Init(
+ GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, kSharedMemoryId, kSharedMemoryOffset);
+ } else {
+ cmd.Init(
+ GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, 0, 0);
}
- TexImage2D cmd;
- cmd.Init(
- GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA,
- GL_UNSIGNED_BYTE, 0, 0);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_CALL(*gl_, TexSubImage2D(
GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight - 1, GL_RGBA, GL_UNSIGNED_BYTE,
@@ -5005,6 +4895,512 @@ TEST_F(GLES2DecoderTest, RequestExtensionCHROMIUMBadBucket) {
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
}
+TEST_F(GLES2DecoderTest, TexSubImage2DClearsAfterTexImage2DNULL) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ 0, 0);
+ SetupClearTextureExpections(
+ kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D,
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, 2, 2);
+ EXPECT_CALL(*gl_, TexSubImage2D(
+ GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ shared_memory_address_))
+ .Times(1)
+ .RetiresOnSaturation();
+ TexSubImage2D cmd;
+ cmd.Init(
+ GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ // Test if we call it again it does not clear.
+ EXPECT_CALL(*gl_, TexSubImage2D(
+ GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ shared_memory_address_))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest,
+ TexSubImage2DDoesNotClearAfterTexImage2DWithDataThenNULL) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ // Put in data (so it should be marked as cleared)
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset);
+ // Put in no data.
+ TexImage2D tex_cmd;
+ tex_cmd.Init(
+ GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
+ // There is no expectation. Same size, no data = no-op.
+ EXPECT_EQ(error::kNoError, ExecuteCmd(tex_cmd));
+ EXPECT_CALL(*gl_, TexSubImage2D(
+ GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ shared_memory_address_))
+ .Times(1)
+ .RetiresOnSaturation();
+ TexSubImage2D cmd;
+ cmd.Init(
+ GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawArraysClearsAfterTexImage2DNULL) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ // Create an uncleared texture with 2 levels.
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ 0, 0);
+ DoTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ 0, 0);
+ // Expect 2 levels will be cleared.
+ SetupClearTextureExpections(
+ kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D,
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, 2, 2);
+ SetupClearTextureExpections(
+ kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D,
+ 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, 1);
+ AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
+ SetupExpectationsForApplyingDefaultDirtyState();
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawElementsClearsAfterTexImage2DNULL) {
+ SetupIndexBuffer();
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ // Create an uncleared texture with 2 levels.
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ 0, 0);
+ DoTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ 0, 0);
+ // Expect 2 levels will be cleared.
+ SetupClearTextureExpections(
+ kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D,
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, 2, 2);
+ SetupClearTextureExpections(
+ kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D,
+ 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, 1);
+ AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, 0);
+ SetupExpectationsForApplyingDefaultDirtyState();
+ EXPECT_CALL(*gl_, DrawElements(GL_TRIANGLES, kValidIndexRangeCount,
+ GL_UNSIGNED_SHORT,
+ BufferOffset(kValidIndexRangeStart * 2)))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawElements cmd;
+ cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawClearsAfterTexImage2DNULLInFBO) {
+ const GLuint kFBOClientTextureId = 4100;
+ const GLuint kFBOServiceTextureId = 4101;
+
+ // Register a texture id.
+ EXPECT_CALL(*gl_, GenTextures(_, _))
+ .WillOnce(SetArgumentPointee<1>(kFBOServiceTextureId))
+ .RetiresOnSaturation();
+ GenHelper<GenTexturesImmediate>(kFBOClientTextureId);
+
+ // Setup "render to" texture.
+ DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
+ DoBindFramebuffer(
+ GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
+ DoFramebufferTexture2D(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ kFBOClientTextureId, kFBOServiceTextureId, 0, GL_NO_ERROR);
+
+ // Setup "render from" texture.
+ SetupTexture();
+
+ SetupExpectationsForFramebufferClearing(
+ GL_FRAMEBUFFER, // target
+ GL_COLOR_BUFFER_BIT, // clear bits
+ 0, 0, 0, 0, // color
+ 0, // stencil
+ 1.0f, // depth
+ false); // scissor test
+
+ AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
+ SetupExpectationsForApplyingDirtyState(
+ false, // Framebuffer is RGB
+ false, // Framebuffer has depth
+ false, // Framebuffer has stencil
+ 0x1111, // color bits
+ false, // depth mask
+ false, // depth enabled
+ 0, // front stencil mask
+ 0, // back stencil mask
+ false); // stencil enabled
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawWitFBOThatCantClearDoesNotDraw) {
+ const GLuint kFBOClientTextureId = 4100;
+ const GLuint kFBOServiceTextureId = 4101;
+
+ // Register a texture id.
+ EXPECT_CALL(*gl_, GenTextures(_, _))
+ .WillOnce(SetArgumentPointee<1>(kFBOServiceTextureId))
+ .RetiresOnSaturation();
+ GenHelper<GenTexturesImmediate>(kFBOClientTextureId);
+
+ // Setup "render to" texture.
+ DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
+ DoBindFramebuffer(
+ GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
+ DoFramebufferTexture2D(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ kFBOClientTextureId, kFBOServiceTextureId, 0, GL_NO_ERROR);
+
+ // Setup "render from" texture.
+ SetupTexture();
+
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
+ .WillOnce(Return(GL_FRAMEBUFFER_UNSUPPORTED))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, DrawArrays(_, _, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_FRAMEBUFFER_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, CopyTexImage2DMarksTextureAsCleared) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+
+ TextureManager* manager = group().texture_manager();
+ TextureManager::TextureInfo* info =
+ manager->GetTextureInfo(client_texture_id_);
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, CopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 1, 1, 0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ CopyTexImage2D cmd;
+ cmd.Init(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 1, 1, 0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+
+ EXPECT_TRUE(info->SafeToRenderFrom());
+}
+
+TEST_F(GLES2DecoderTest, CopyTexSubImage2DClearsUnclearedTexture) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
+
+ SetupClearTextureExpections(
+ kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D,
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, 2, 2);
+ EXPECT_CALL(*gl_, CopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1))
+ .Times(1)
+ .RetiresOnSaturation();
+ CopyTexSubImage2D cmd;
+ cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderManualInitTest, CompressedImage2DMarksTextureAsCleared) {
+ InitDecoder(
+ "GL_EXT_texture_compression_s3tc", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, CompressedTexImage2D(
+ GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0, 16, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ CompressedTexImage2D cmd;
+ cmd.Init(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
+ 16, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ TextureManager* manager = group().texture_manager();
+ TextureManager::TextureInfo* info =
+ manager->GetTextureInfo(client_texture_id_);
+ EXPECT_TRUE(info->SafeToRenderFrom());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, UnClearedAttachmentsGetClearedOnClear) {
+ const GLuint kFBOClientTextureId = 4100;
+ const GLuint kFBOServiceTextureId = 4101;
+
+ // Register a texture id.
+ EXPECT_CALL(*gl_, GenTextures(_, _))
+ .WillOnce(SetArgumentPointee<1>(kFBOServiceTextureId))
+ .RetiresOnSaturation();
+ GenHelper<GenTexturesImmediate>(kFBOClientTextureId);
+
+ // Setup "render to" texture.
+ DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
+ DoBindFramebuffer(
+ GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
+ DoFramebufferTexture2D(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ kFBOClientTextureId, kFBOServiceTextureId, 0, GL_NO_ERROR);
+
+ // Setup "render from" texture.
+ SetupTexture();
+
+ SetupExpectationsForFramebufferClearing(
+ GL_FRAMEBUFFER, // target
+ GL_COLOR_BUFFER_BIT, // clear bits
+ 0, 0, 0, 0, // color
+ 0, // stencil
+ 1.0f, // depth
+ false); // scissor test
+ SetupExpectationsForApplyingDirtyState(
+ false, // Framebuffer is RGB
+ false, // Framebuffer has depth
+ false, // Framebuffer has stencil
+ 0x1111, // color bits
+ false, // depth mask
+ false, // depth enabled
+ 0, // front stencil mask
+ 0, // back stencil mask
+ false); // stencil enabled
+ EXPECT_CALL(*gl_, Clear(GL_COLOR_BUFFER_BIT))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ Clear cmd;
+ cmd.Init(GL_COLOR_BUFFER_BIT);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, UnClearedAttachmentsGetClearedOnReadPixels) {
+ const GLuint kFBOClientTextureId = 4100;
+ const GLuint kFBOServiceTextureId = 4101;
+
+ // Register a texture id.
+ EXPECT_CALL(*gl_, GenTextures(_, _))
+ .WillOnce(SetArgumentPointee<1>(kFBOServiceTextureId))
+ .RetiresOnSaturation();
+ GenHelper<GenTexturesImmediate>(kFBOClientTextureId);
+
+ // Setup "render to" texture.
+ DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
+ DoBindFramebuffer(
+ GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
+ DoFramebufferTexture2D(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ kFBOClientTextureId, kFBOServiceTextureId, 0, GL_NO_ERROR);
+
+ // Setup "render from" texture.
+ SetupTexture();
+
+ SetupExpectationsForFramebufferClearing(
+ GL_FRAMEBUFFER, // target
+ GL_COLOR_BUFFER_BIT, // clear bits
+ 0, 0, 0, 0, // color
+ 0, // stencil
+ 1.0f, // depth
+ false); // scissor test
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, ReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ typedef ReadPixels::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ uint32 result_shm_id = kSharedMemoryId;
+ uint32 result_shm_offset = kSharedMemoryOffset;
+ uint32 pixels_shm_id = kSharedMemoryId;
+ uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(*result);
+ ReadPixels cmd;
+ cmd.Init(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixels_shm_id, pixels_shm_offset,
+ result_shm_id, result_shm_offset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawClearsAfterRenderbufferStorageInFBO) {
+ SetupTexture();
+ DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
+ kServiceRenderbufferId);
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ DoRenderbufferStorage(
+ GL_RENDERBUFFER, GL_RGBA4, GL_RGBA, 100, 50, GL_NO_ERROR);
+ DoFramebufferRenderbuffer(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
+ client_renderbuffer_id_, kServiceRenderbufferId, GL_NO_ERROR);
+
+ SetupExpectationsForFramebufferClearing(
+ GL_FRAMEBUFFER, // target
+ GL_COLOR_BUFFER_BIT, // clear bits
+ 0, 0, 0, 0, // color
+ 0, // stencil
+ 1.0f, // depth
+ false); // scissor test
+
+ AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
+ SetupExpectationsForApplyingDirtyState(
+ false, // Framebuffer is RGB
+ false, // Framebuffer has depth
+ false, // Framebuffer has stencil
+ 0x1111, // color bits
+ false, // depth mask
+ false, // depth enabled
+ 0, // front stencil mask
+ 0, // back stencil mask
+ false); // stencil enabled
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, DrawArraysClearsAfterTexImage2DNULLCubemap) {
+ static const GLenum faces[] = {
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
+ };
+ SetupCubemapProgram();
+ DoBindTexture(GL_TEXTURE_CUBE_MAP, client_texture_id_, kServiceTextureId);
+ // Fill out all the faces for 2 levels, leave 2 uncleared.
+ for (int ii = 0; ii < 6; ++ii) {
+ GLenum face = faces[ii];
+ int32 shm_id =
+ (face == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y) ? 0 : kSharedMemoryId;
+ uint32 shm_offset =
+ (face == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y) ? 0 : kSharedMemoryOffset;
+ DoTexImage2D(face, 0, GL_RGBA, 2, 2, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, shm_id, shm_offset);
+ DoTexImage2D(face, 1, GL_RGBA, 1, 1, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, shm_id, shm_offset);
+ }
+ // Expect 2 levels will be cleared.
+ SetupClearTextureExpections(
+ kServiceTextureId, kServiceTextureId, GL_TEXTURE_CUBE_MAP,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA, GL_UNSIGNED_BYTE, 2, 2);
+ SetupClearTextureExpections(
+ kServiceTextureId, kServiceTextureId, GL_TEXTURE_CUBE_MAP,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, 1);
+ AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
+ SetupExpectationsForApplyingDefaultDirtyState();
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderWithShaderTest,
+ DrawClearsAfterRenderbuffersWithMultipleAttachments) {
+ const GLuint kFBOClientTextureId = 4100;
+ const GLuint kFBOServiceTextureId = 4101;
+
+ // Register a texture id.
+ EXPECT_CALL(*gl_, GenTextures(_, _))
+ .WillOnce(SetArgumentPointee<1>(kFBOServiceTextureId))
+ .RetiresOnSaturation();
+ GenHelper<GenTexturesImmediate>(kFBOClientTextureId);
+
+ // Setup "render to" texture.
+ DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
+ DoBindFramebuffer(
+ GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
+ DoFramebufferTexture2D(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ kFBOClientTextureId, kFBOServiceTextureId, 0, GL_NO_ERROR);
+
+ DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
+ kServiceRenderbufferId);
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ DoRenderbufferStorage(
+ GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT,
+ 1, 1, GL_NO_ERROR);
+ DoFramebufferRenderbuffer(
+ GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
+ client_renderbuffer_id_, kServiceRenderbufferId, GL_NO_ERROR);
+
+ SetupTexture();
+ SetupExpectationsForFramebufferClearing(
+ GL_FRAMEBUFFER, // target
+ GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, // clear bits
+ 0, 0, 0, 0, // color
+ 0, // stencil
+ 1.0f, // depth
+ false); // scissor test
+
+ AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
+ SetupExpectationsForApplyingDirtyState(
+ false, // Framebuffer is RGB
+ true, // Framebuffer has depth
+ false, // Framebuffer has stencil
+ 0x1111, // color bits
+ true, // depth mask
+ false, // depth enabled
+ 0, // front stencil mask
+ 0, // back stencil mask
+ false); // stencil enabled
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+
+
// TODO(gman): Complete this test.
// TEST_F(GLES2DecoderTest, CompressedTexImage2DGLError) {
// }
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc
index 5a52f8a..19ea2bc 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc
@@ -54,8 +54,16 @@ void GLES2DecoderTestBase::SpecializedSetup<GenerateMipmap, 0>(
template <>
void GLES2DecoderTestBase::SpecializedSetup<CheckFramebufferStatus, 0>(
bool /* valid */) {
+ // Give it a valid framebuffer.
+ DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
+ kServiceRenderbufferId);
DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
kServiceFramebufferId);
+ DoRenderbufferStorage(
+ GL_RENDERBUFFER, GL_RGBA4, GL_RGBA, 1, 1, GL_NO_ERROR);
+ DoFramebufferRenderbuffer(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
+ client_renderbuffer_id_, kServiceRenderbufferId, GL_NO_ERROR);
};
template <>
@@ -91,7 +99,7 @@ void GLES2DecoderTestBase::SpecializedSetup<CopyTexSubImage2D, 0>(bool valid) {
DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
DoTexImage2D(
GL_TEXTURE_2D, 2, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
- 0, 0);
+ kSharedMemoryId, kSharedMemoryOffset);
}
};
@@ -116,13 +124,6 @@ void GLES2DecoderTestBase::SpecializedSetup<FramebufferRenderbuffer, 0>(
if (valid) {
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
- .RetiresOnSaturation();
- // Return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT so the code
- // doesn't try to clear the buffer. That is tested else where.
- EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
- .WillOnce(Return(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT))
- .RetiresOnSaturation();
- EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
}
@@ -136,13 +137,6 @@ void GLES2DecoderTestBase::SpecializedSetup<FramebufferTexture2D, 0>(
if (valid) {
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
- .RetiresOnSaturation();
- // Return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT so the code
- // doesn't try to clear the buffer. That is tested else where.
- EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
- .WillOnce(Return(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT))
- .RetiresOnSaturation();
- EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
}
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
index 2f6c5e4..70c269d 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -16,6 +16,7 @@
#include "gpu/command_buffer/service/program_manager.h"
#include "gpu/command_buffer/service/test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/gl/gl_implementation.h"
using ::gfx::MockGLInterface;
using ::testing::_;
@@ -41,7 +42,9 @@ GLES2DecoderTestBase::GLES2DecoderTestBase()
client_renderbuffer_id_(103),
client_shader_id_(104),
client_texture_id_(106),
- client_element_buffer_id_(107) {
+ client_element_buffer_id_(107),
+ client_vertex_shader_id_(121),
+ client_fragment_shader_id_(122) {
memset(immediate_buffer_, 0xEE, sizeof(immediate_buffer_));
}
@@ -302,7 +305,30 @@ void GLES2DecoderTestBase::SetBucketAsCString(
}
}
-void GLES2DecoderTestBase::SetupExpectationsForFramebufferAttachment(
+void GLES2DecoderTestBase::SetupClearTextureExpections(
+ GLuint service_id,
+ GLuint old_service_id,
+ GLenum bind_target,
+ GLenum target,
+ GLint level,
+ GLenum format,
+ GLenum type,
+ GLsizei width,
+ GLsizei height) {
+ EXPECT_CALL(*gl_, BindTexture(bind_target, service_id))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, TexImage2D(
+ target, level, format, width, height, 0, format, type, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindTexture(bind_target, old_service_id))
+ .Times(1)
+ .RetiresOnSaturation();
+}
+
+void GLES2DecoderTestBase::SetupExpectationsForFramebufferClearing(
+ GLenum target,
GLuint clear_bits,
GLclampf restore_red,
GLclampf restore_green,
@@ -311,15 +337,16 @@ void GLES2DecoderTestBase::SetupExpectationsForFramebufferAttachment(
GLuint restore_stencil,
GLclampf restore_depth,
bool restore_scissor_test) {
- InSequence sequence;
- EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
+ // TODO(gman): Figure out why InSequence stopped working.
+ // InSequence sequence;
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(target))
.WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
.RetiresOnSaturation();
if ((clear_bits & GL_COLOR_BUFFER_BIT) != 0) {
- EXPECT_CALL(*gl_, ClearColor(0, 0, 0, 0))
+ EXPECT_CALL(*gl_, ClearColor(0.0f, 0.0f, 0.0f, 0.0f))
.Times(1)
.RetiresOnSaturation();
- EXPECT_CALL(*gl_, ColorMask(1, 1, 1, 1))
+ EXPECT_CALL(*gl_, ColorMask(true, true, true, true))
.Times(1)
.RetiresOnSaturation();
}
@@ -578,6 +605,65 @@ void GLES2DecoderTestBase::DoTexImage2D(
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
}
+void GLES2DecoderTestBase::DoRenderbufferStorage(
+ GLenum target, GLenum internal_format, GLenum actual_format,
+ GLsizei width, GLsizei height, GLenum error) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, RenderbufferStorageEXT(
+ target, actual_format, width, height))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(error))
+ .RetiresOnSaturation();
+ RenderbufferStorage cmd;
+ cmd.Init(target, internal_format, width, height);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+void GLES2DecoderTestBase::DoFramebufferTexture2D(
+ GLenum target, GLenum attachment, GLenum textarget,
+ GLuint texture_client_id, GLuint texture_service_id, GLint level,
+ GLenum error) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, FramebufferTexture2DEXT(
+ target, attachment, textarget, texture_service_id, level))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(error))
+ .RetiresOnSaturation();
+ FramebufferTexture2D cmd;
+ cmd.Init(target, attachment, textarget, texture_client_id, level);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+void GLES2DecoderTestBase::DoFramebufferRenderbuffer(
+ GLenum target,
+ GLenum attachment,
+ GLenum renderbuffer_target,
+ GLuint renderbuffer_client_id,
+ GLuint renderbuffer_service_id,
+ GLenum error) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(
+ target, attachment, renderbuffer_target, renderbuffer_service_id))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(error))
+ .RetiresOnSaturation();
+ FramebufferRenderbuffer cmd;
+ cmd.Init(target, attachment, renderbuffer_target, renderbuffer_client_id);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
void GLES2DecoderTestBase::DoVertexAttribPointer(
GLuint index, GLint size, GLenum type, GLsizei stride, GLuint offset) {
EXPECT_CALL(*gl_,
@@ -627,14 +713,57 @@ const uint32 GLES2DecoderTestBase::kInvalidClientId;
const int GLES2DecoderTestBase::kBackBufferWidth;
const int GLES2DecoderTestBase::kBackBufferHeight;
+
+const GLuint GLES2DecoderTestBase::kServiceVertexShaderId;
+const GLuint GLES2DecoderTestBase::kServiceFragmentShaderId;
+
+const GLsizei GLES2DecoderTestBase::kNumVertices;
+const GLsizei GLES2DecoderTestBase::kNumIndices;
+const int GLES2DecoderTestBase::kValidIndexRangeStart;
+const int GLES2DecoderTestBase::kValidIndexRangeCount;
+const int GLES2DecoderTestBase::kInvalidIndexRangeStart;
+const int GLES2DecoderTestBase::kInvalidIndexRangeCount;
+const int GLES2DecoderTestBase::kOutOfRangeIndexRangeEnd;
+const GLuint GLES2DecoderTestBase::kMaxValidIndex;
+
+const GLint GLES2DecoderTestBase::kMaxAttribLength;
+const GLint GLES2DecoderTestBase::kAttrib1Size;
+const GLint GLES2DecoderTestBase::kAttrib2Size;
+const GLint GLES2DecoderTestBase::kAttrib3Size;
+const GLint GLES2DecoderTestBase::kAttrib1Location;
+const GLint GLES2DecoderTestBase::kAttrib2Location;
+const GLint GLES2DecoderTestBase::kAttrib3Location;
+const GLenum GLES2DecoderTestBase::kAttrib1Type;
+const GLenum GLES2DecoderTestBase::kAttrib2Type;
+const GLenum GLES2DecoderTestBase::kAttrib3Type;
+const GLint GLES2DecoderTestBase::kInvalidAttribLocation;
+const GLint GLES2DecoderTestBase::kBadAttribIndex;
+
+const GLint GLES2DecoderTestBase::kMaxUniformLength;
+const GLint GLES2DecoderTestBase::kUniform1Size;
+const GLint GLES2DecoderTestBase::kUniform2Size;
+const GLint GLES2DecoderTestBase::kUniform3Size;
+const GLint GLES2DecoderTestBase::kUniform1Location;
+const GLint GLES2DecoderTestBase::kUniform2Location;
+const GLint GLES2DecoderTestBase::kUniform2ElementLocation;
+const GLint GLES2DecoderTestBase::kUniform3Location;
+const GLenum GLES2DecoderTestBase::kUniform1Type;
+const GLenum GLES2DecoderTestBase::kUniform2Type;
+const GLenum GLES2DecoderTestBase::kUniform3Type;
+const GLenum GLES2DecoderTestBase::kUniformCubemapType;
+const GLint GLES2DecoderTestBase::kInvalidUniformLocation;
+const GLint GLES2DecoderTestBase::kBadUniformIndex;
+
#endif
-void GLES2DecoderWithShaderTestBase::SetUp() {
- GLES2DecoderTestBase::SetUp();
- SetupDefaultProgram();
-}
+const char* GLES2DecoderTestBase::kAttrib1Name = "attrib1";
+const char* GLES2DecoderTestBase::kAttrib2Name = "attrib2";
+const char* GLES2DecoderTestBase::kAttrib3Name = "attrib3";
+const char* GLES2DecoderTestBase::kUniform1Name = "uniform1";
+const char* GLES2DecoderTestBase::kUniform2Name = "uniform2[0]";
+const char* GLES2DecoderTestBase::kUniform3Name = "uniform3[0]";
-void GLES2DecoderWithShaderTestBase::SetupDefaultProgram() {
+void GLES2DecoderTestBase::SetupDefaultProgram() {
{
static AttribInfo attribs[] = {
{ kAttrib1Name, kAttrib1Size, kAttrib1Type, kAttrib1Location, },
@@ -662,6 +791,34 @@ void GLES2DecoderWithShaderTestBase::SetupDefaultProgram() {
}
}
+void GLES2DecoderTestBase::SetupCubemapProgram() {
+ {
+ static AttribInfo attribs[] = {
+ { kAttrib1Name, kAttrib1Size, kAttrib1Type, kAttrib1Location, },
+ { kAttrib2Name, kAttrib2Size, kAttrib2Type, kAttrib2Location, },
+ { kAttrib3Name, kAttrib3Size, kAttrib3Type, kAttrib3Location, },
+ };
+ static UniformInfo uniforms[] = {
+ { kUniform1Name, kUniform1Size, kUniformCubemapType, kUniform1Location, },
+ { kUniform2Name, kUniform2Size, kUniform2Type, kUniform2Location, },
+ { kUniform3Name, kUniform3Size, kUniform3Type, kUniform3Location, },
+ };
+ SetupShader(attribs, arraysize(attribs), uniforms, arraysize(uniforms),
+ client_program_id_, kServiceProgramId,
+ client_vertex_shader_id_, kServiceVertexShaderId,
+ client_fragment_shader_id_, kServiceFragmentShaderId);
+ }
+
+ {
+ EXPECT_CALL(*gl_, UseProgram(kServiceProgramId))
+ .Times(1)
+ .RetiresOnSaturation();
+ UseProgram cmd;
+ cmd.Init(client_program_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ }
+}
+
void GLES2DecoderWithShaderTestBase::TearDown() {
GLES2DecoderTestBase::TearDown();
}
@@ -794,7 +951,7 @@ void GLES2DecoderTestBase::SetupShader(
EXPECT_EQ(error::kNoError, ExecuteCmd(link_cmd));
}
-void GLES2DecoderWithShaderTestBase::DoEnableVertexAttribArray(GLint index) {
+void GLES2DecoderTestBase::DoEnableVertexAttribArray(GLint index) {
EXPECT_CALL(*gl_, EnableVertexAttribArray(index))
.Times(1)
.RetiresOnSaturation();
@@ -803,7 +960,7 @@ void GLES2DecoderWithShaderTestBase::DoEnableVertexAttribArray(GLint index) {
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
}
-void GLES2DecoderWithShaderTestBase::DoBufferData(GLenum target, GLsizei size) {
+void GLES2DecoderTestBase::DoBufferData(GLenum target, GLsizei size) {
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
@@ -818,7 +975,7 @@ void GLES2DecoderWithShaderTestBase::DoBufferData(GLenum target, GLsizei size) {
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
}
-void GLES2DecoderWithShaderTestBase::DoBufferSubData(
+void GLES2DecoderTestBase::DoBufferSubData(
GLenum target, GLint offset, GLsizei size, const void* data) {
EXPECT_CALL(*gl_, BufferSubData(target, offset, size,
shared_memory_address_))
@@ -830,14 +987,14 @@ void GLES2DecoderWithShaderTestBase::DoBufferSubData(
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
}
-void GLES2DecoderWithShaderTestBase::SetupVertexBuffer() {
+void GLES2DecoderTestBase::SetupVertexBuffer() {
DoEnableVertexAttribArray(1);
DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, kServiceBufferId);
GLfloat f = 0;
DoBufferData(GL_ARRAY_BUFFER, kNumVertices * 2 * sizeof(f));
}
-void GLES2DecoderWithShaderTestBase::SetupIndexBuffer() {
+void GLES2DecoderTestBase::SetupIndexBuffer() {
DoBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
client_element_buffer_id_,
kServiceElementBufferId);
@@ -848,68 +1005,68 @@ void GLES2DecoderWithShaderTestBase::SetupIndexBuffer() {
DoBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 2, sizeof(indices) - 2, &indices[1]);
}
-void GLES2DecoderWithShaderTestBase::SetupTexture() {
+void GLES2DecoderTestBase::SetupTexture() {
DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
- 0, 0);
+ kSharedMemoryId, kSharedMemoryOffset);
};
-void GLES2DecoderWithShaderTestBase::DeleteVertexBuffer() {
+void GLES2DecoderTestBase::DeleteVertexBuffer() {
DoDeleteBuffer(client_buffer_id_, kServiceBufferId);
}
-void GLES2DecoderWithShaderTestBase::DeleteIndexBuffer() {
+void GLES2DecoderTestBase::DeleteIndexBuffer() {
DoDeleteBuffer(client_element_buffer_id_, kServiceElementBufferId);
}
-// GCC requires these declarations, but MSVC requires they not be present
-#ifndef COMPILER_MSVC
-const GLuint GLES2DecoderWithShaderTestBase::kServiceVertexShaderId;
-const GLuint GLES2DecoderWithShaderTestBase::kServiceFragmentShaderId;
-
-const GLsizei GLES2DecoderWithShaderTestBase::kNumVertices;
-const GLsizei GLES2DecoderWithShaderTestBase::kNumIndices;
-const int GLES2DecoderWithShaderTestBase::kValidIndexRangeStart;
-const int GLES2DecoderWithShaderTestBase::kValidIndexRangeCount;
-const int GLES2DecoderWithShaderTestBase::kInvalidIndexRangeStart;
-const int GLES2DecoderWithShaderTestBase::kInvalidIndexRangeCount;
-const int GLES2DecoderWithShaderTestBase::kOutOfRangeIndexRangeEnd;
-const GLuint GLES2DecoderWithShaderTestBase::kMaxValidIndex;
-
-const GLint GLES2DecoderWithShaderTestBase::kMaxAttribLength;
-const GLint GLES2DecoderWithShaderTestBase::kAttrib1Size;
-const GLint GLES2DecoderWithShaderTestBase::kAttrib2Size;
-const GLint GLES2DecoderWithShaderTestBase::kAttrib3Size;
-const GLint GLES2DecoderWithShaderTestBase::kAttrib1Location;
-const GLint GLES2DecoderWithShaderTestBase::kAttrib2Location;
-const GLint GLES2DecoderWithShaderTestBase::kAttrib3Location;
-const GLenum GLES2DecoderWithShaderTestBase::kAttrib1Type;
-const GLenum GLES2DecoderWithShaderTestBase::kAttrib2Type;
-const GLenum GLES2DecoderWithShaderTestBase::kAttrib3Type;
-const GLint GLES2DecoderWithShaderTestBase::kInvalidAttribLocation;
-const GLint GLES2DecoderWithShaderTestBase::kBadAttribIndex;
-
-const GLint GLES2DecoderWithShaderTestBase::kMaxUniformLength;
-const GLint GLES2DecoderWithShaderTestBase::kUniform1Size;
-const GLint GLES2DecoderWithShaderTestBase::kUniform2Size;
-const GLint GLES2DecoderWithShaderTestBase::kUniform3Size;
-const GLint GLES2DecoderWithShaderTestBase::kUniform1Location;
-const GLint GLES2DecoderWithShaderTestBase::kUniform2Location;
-const GLint GLES2DecoderWithShaderTestBase::kUniform2ElementLocation;
-const GLint GLES2DecoderWithShaderTestBase::kUniform3Location;
-const GLenum GLES2DecoderWithShaderTestBase::kUniform1Type;
-const GLenum GLES2DecoderWithShaderTestBase::kUniform2Type;
-const GLenum GLES2DecoderWithShaderTestBase::kUniform3Type;
-const GLint GLES2DecoderWithShaderTestBase::kInvalidUniformLocation;
-const GLint GLES2DecoderWithShaderTestBase::kBadUniformIndex;
-#endif
+void GLES2DecoderTestBase::AddExpectationsForSimulatedAttrib0WithError(
+ GLsizei num_vertices, GLuint buffer_id, GLenum error) {
+ if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) {
+ return;
+ }
-const char* GLES2DecoderWithShaderTestBase::kAttrib1Name = "attrib1";
-const char* GLES2DecoderWithShaderTestBase::kAttrib2Name = "attrib2";
-const char* GLES2DecoderWithShaderTestBase::kAttrib3Name = "attrib3";
-const char* GLES2DecoderWithShaderTestBase::kUniform1Name = "uniform1";
-const char* GLES2DecoderWithShaderTestBase::kUniform2Name = "uniform2[0]";
-const char* GLES2DecoderWithShaderTestBase::kUniform3Name = "uniform3[0]";
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(error))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, kServiceAttrib0BufferId))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BufferData(GL_ARRAY_BUFFER,
+ num_vertices * sizeof(GLfloat) * 4,
+ _, GL_DYNAMIC_DRAW))
+ .Times(1)
+ .RetiresOnSaturation();
+ if (error == GL_NO_ERROR) {
+ EXPECT_CALL(*gl_, BufferSubData(
+ GL_ARRAY_BUFFER, 0, num_vertices * sizeof(GLfloat) * 4, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, VertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, 0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, VertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, buffer_id))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+}
+
+void GLES2DecoderTestBase::AddExpectationsForSimulatedAttrib0(
+ GLsizei num_vertices, GLuint buffer_id) {
+ AddExpectationsForSimulatedAttrib0WithError(
+ num_vertices, buffer_id, GL_NO_ERROR);
+}
+
+void GLES2DecoderWithShaderTestBase::SetUp() {
+ GLES2DecoderTestBase::SetUp();
+ SetupDefaultProgram();
+}
} // namespace gles2
} // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
index 4ebbe24..3cb5eab 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -66,6 +66,52 @@ class GLES2DecoderTestBase : public testing::Test {
static const int kBackBufferWidth = 128;
static const int kBackBufferHeight = 64;
+ static const GLuint kServiceVertexShaderId = 321;
+ static const GLuint kServiceFragmentShaderId = 322;
+
+ static const GLsizei kNumVertices = 100;
+ static const GLsizei kNumIndices = 10;
+ static const int kValidIndexRangeStart = 1;
+ static const int kValidIndexRangeCount = 7;
+ static const int kInvalidIndexRangeStart = 0;
+ static const int kInvalidIndexRangeCount = 7;
+ static const int kOutOfRangeIndexRangeEnd = 10;
+ static const GLuint kMaxValidIndex = 7;
+
+ static const GLint kMaxAttribLength = 10;
+ static const char* kAttrib1Name;
+ static const char* kAttrib2Name;
+ static const char* kAttrib3Name;
+ static const GLint kAttrib1Size = 1;
+ static const GLint kAttrib2Size = 1;
+ static const GLint kAttrib3Size = 1;
+ static const GLint kAttrib1Location = 0;
+ static const GLint kAttrib2Location = 1;
+ static const GLint kAttrib3Location = 2;
+ static const GLenum kAttrib1Type = GL_FLOAT_VEC4;
+ static const GLenum kAttrib2Type = GL_FLOAT_VEC2;
+ static const GLenum kAttrib3Type = GL_FLOAT_VEC3;
+ static const GLint kInvalidAttribLocation = 30;
+ static const GLint kBadAttribIndex = kNumVertexAttribs;
+
+ static const GLint kMaxUniformLength = 12;
+ static const char* kUniform1Name;
+ static const char* kUniform2Name;
+ static const char* kUniform3Name;
+ static const GLint kUniform1Size = 1;
+ static const GLint kUniform2Size = 3;
+ static const GLint kUniform3Size = 2;
+ static const GLint kUniform1Location = 3;
+ static const GLint kUniform2Location = 10;
+ static const GLint kUniform2ElementLocation = 12;
+ static const GLint kUniform3Location = 20;
+ static const GLenum kUniform1Type = GL_SAMPLER_2D;
+ static const GLenum kUniform2Type = GL_INT_VEC2;
+ static const GLenum kUniform3Type = GL_FLOAT_VEC3;
+ static const GLenum kUniformCubemapType = GL_SAMPLER_CUBE;
+ static const GLint kInvalidUniformLocation = 30;
+ static const GLint kBadUniformIndex = 1000;
+
// Template to call glGenXXX functions.
template <typename T>
void GenHelper(GLuint client_id) {
@@ -197,6 +243,9 @@ class GLES2DecoderTestBase : public testing::Test {
// Setups up a shader for testing glUniform.
void SetupShaderForUniform();
+ void SetupDefaultProgram();
+ void SetupCubemapProgram();
+ void SetupTexture();
// Note that the error is returned as GLint instead of GLenum.
// This is because there is a mismatch in the types of GLenum and
@@ -228,14 +277,56 @@ class GLES2DecoderTestBase : public testing::Test {
void DoDeleteShader(GLuint client_id, GLuint service_id);
void DoDeleteTexture(GLuint client_id, GLuint service_id);
- void DoTexImage2D(GLenum target, GLint level, GLenum internal_format,
- GLsizei width, GLsizei height, GLint border,
- GLenum format, GLenum type,
- uint32 shared_memory_id, uint32 shared_memory_offset);
+ void DoTexImage2D(
+ GLenum target, GLint level, GLenum internal_format,
+ GLsizei width, GLsizei height, GLint border,
+ GLenum format, GLenum type,
+ uint32 shared_memory_id, uint32 shared_memory_offset);
+ void DoRenderbufferStorage(
+ GLenum target, GLenum internal_format, GLenum actual_format,
+ GLsizei width, GLsizei height, GLenum error);
+ void DoFramebufferRenderbuffer(
+ GLenum target,
+ GLenum attachment,
+ GLenum renderbuffer_target,
+ GLuint renderbuffer_client_id,
+ GLuint renderbuffer_service_id,
+ GLenum error);
+ void DoFramebufferTexture2D(
+ GLenum target, GLenum attachment, GLenum tex_target,
+ GLuint texture_client_id, GLuint texture_service_id,
+ GLint level, GLenum error);
void DoVertexAttribPointer(
GLuint index, GLint size, GLenum type, GLsizei stride, GLuint offset);
- void SetupExpectationsForFramebufferAttachment(
+ void DoEnableVertexAttribArray(GLint index);
+
+ void DoBufferData(GLenum target, GLsizei size);
+
+ void DoBufferSubData(
+ GLenum target, GLint offset, GLsizei size, const void* data);
+
+ void SetupVertexBuffer();
+
+ void SetupIndexBuffer();
+
+ void DeleteVertexBuffer();
+
+ void DeleteIndexBuffer();
+
+ void SetupClearTextureExpections(
+ GLuint service_id,
+ GLuint old_service_id,
+ GLenum bind_target,
+ GLenum target,
+ GLint level,
+ GLenum format,
+ GLenum type,
+ GLsizei width,
+ GLsizei height);
+
+ void SetupExpectationsForFramebufferClearing(
+ GLenum target,
GLuint clear_bits,
GLclampf restore_red,
GLclampf restore_green,
@@ -258,6 +349,12 @@ class GLES2DecoderTestBase : public testing::Test {
void SetupExpectationsForApplyingDefaultDirtyState();
+ void AddExpectationsForSimulatedAttrib0WithError(
+ GLsizei num_vertices, GLuint buffer_id, GLenum error);
+
+ void AddExpectationsForSimulatedAttrib0(
+ GLsizei num_vertices, GLuint buffer_id);
+
GLvoid* BufferOffset(unsigned i) {
return static_cast<int8 *>(NULL)+(i);
}
@@ -286,6 +383,8 @@ class GLES2DecoderTestBase : public testing::Test {
GLuint client_shader_id_;
GLuint client_texture_id_;
GLuint client_element_buffer_id_;
+ GLuint client_vertex_shader_id_;
+ GLuint client_fragment_shader_id_;
uint32 shared_memory_id_;
uint32 shared_memory_offset_;
@@ -344,80 +443,13 @@ class GLES2DecoderTestBase : public testing::Test {
class GLES2DecoderWithShaderTestBase : public GLES2DecoderTestBase {
public:
GLES2DecoderWithShaderTestBase()
- : GLES2DecoderTestBase(),
- client_vertex_shader_id_(121),
- client_fragment_shader_id_(122) {
+ : GLES2DecoderTestBase() {
}
- static const GLuint kServiceVertexShaderId = 321;
- static const GLuint kServiceFragmentShaderId = 322;
-
- static const GLsizei kNumVertices = 100;
- static const GLsizei kNumIndices = 10;
- static const int kValidIndexRangeStart = 1;
- static const int kValidIndexRangeCount = 7;
- static const int kInvalidIndexRangeStart = 0;
- static const int kInvalidIndexRangeCount = 7;
- static const int kOutOfRangeIndexRangeEnd = 10;
- static const GLuint kMaxValidIndex = 7;
-
- static const GLint kMaxAttribLength = 10;
- static const char* kAttrib1Name;
- static const char* kAttrib2Name;
- static const char* kAttrib3Name;
- static const GLint kAttrib1Size = 1;
- static const GLint kAttrib2Size = 1;
- static const GLint kAttrib3Size = 1;
- static const GLint kAttrib1Location = 0;
- static const GLint kAttrib2Location = 1;
- static const GLint kAttrib3Location = 2;
- static const GLenum kAttrib1Type = GL_FLOAT_VEC4;
- static const GLenum kAttrib2Type = GL_FLOAT_VEC2;
- static const GLenum kAttrib3Type = GL_FLOAT_VEC3;
- static const GLint kInvalidAttribLocation = 30;
- static const GLint kBadAttribIndex = kNumVertexAttribs;
-
- static const GLint kMaxUniformLength = 12;
- static const char* kUniform1Name;
- static const char* kUniform2Name;
- static const char* kUniform3Name;
- static const GLint kUniform1Size = 1;
- static const GLint kUniform2Size = 3;
- static const GLint kUniform3Size = 2;
- static const GLint kUniform1Location = 3;
- static const GLint kUniform2Location = 10;
- static const GLint kUniform2ElementLocation = 12;
- static const GLint kUniform3Location = 20;
- static const GLenum kUniform1Type = GL_SAMPLER_2D;
- static const GLenum kUniform2Type = GL_INT_VEC2;
- static const GLenum kUniform3Type = GL_FLOAT_VEC3;
- static const GLint kInvalidUniformLocation = 30;
- static const GLint kBadUniformIndex = 1000;
-
protected:
virtual void SetUp();
virtual void TearDown();
- void SetupDefaultProgram();
- void SetupTexture();
-
- void DoEnableVertexAttribArray(GLint index);
-
- void DoBufferData(GLenum target, GLsizei size);
-
- void DoBufferSubData(
- GLenum target, GLint offset, GLsizei size, const void* data);
-
- void SetupVertexBuffer();
-
- void SetupIndexBuffer();
-
- void DeleteVertexBuffer();
-
- void DeleteIndexBuffer();
-
- GLuint client_vertex_shader_id_;
- GLuint client_fragment_shader_id_;
};
} // namespace gles2
diff --git a/gpu/command_buffer/service/renderbuffer_manager.cc b/gpu/command_buffer/service/renderbuffer_manager.cc
index a12d66e..5c9ca30 100644
--- a/gpu/command_buffer/service/renderbuffer_manager.cc
+++ b/gpu/command_buffer/service/renderbuffer_manager.cc
@@ -13,7 +13,8 @@ namespace gles2 {
RenderbufferManager::RenderbufferManager(
GLint max_renderbuffer_size, GLint max_samples)
: max_renderbuffer_size_(max_renderbuffer_size),
- max_samples_(max_samples) {
+ max_samples_(max_samples),
+ num_uncleared_renderbuffers_(0) {
}
RenderbufferManager::~RenderbufferManager() {
@@ -34,14 +35,39 @@ void RenderbufferManager::Destroy(bool have_context) {
}
}
+void RenderbufferManager::SetInfo(
+ RenderbufferInfo* renderbuffer,
+ GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
+ DCHECK(renderbuffer);
+ if (!renderbuffer->cleared()) {
+ --num_uncleared_renderbuffers_;
+ }
+ renderbuffer->SetInfo(samples, internalformat, width, height);
+ if (!renderbuffer->cleared()) {
+ ++num_uncleared_renderbuffers_;
+ }
+}
+
+void RenderbufferManager::SetCleared(RenderbufferInfo* renderbuffer) {
+ DCHECK(renderbuffer);
+ if (!renderbuffer->cleared()) {
+ --num_uncleared_renderbuffers_;
+ }
+ renderbuffer->set_cleared();
+ if (!renderbuffer->cleared()) {
+ ++num_uncleared_renderbuffers_;
+ }
+}
+
void RenderbufferManager::CreateRenderbufferInfo(
GLuint client_id, GLuint service_id) {
+ RenderbufferInfo::Ref info(new RenderbufferInfo(service_id));
std::pair<RenderbufferInfoMap::iterator, bool> result =
- renderbuffer_infos_.insert(
- std::make_pair(
- client_id,
- RenderbufferInfo::Ref(new RenderbufferInfo(service_id))));
+ renderbuffer_infos_.insert(std::make_pair(client_id, info));
DCHECK(result.second);
+ if (!info->cleared()) {
+ ++num_uncleared_renderbuffers_;
+ }
}
RenderbufferManager::RenderbufferInfo* RenderbufferManager::GetRenderbufferInfo(
@@ -53,7 +79,11 @@ RenderbufferManager::RenderbufferInfo* RenderbufferManager::GetRenderbufferInfo(
void RenderbufferManager::RemoveRenderbufferInfo(GLuint client_id) {
RenderbufferInfoMap::iterator it = renderbuffer_infos_.find(client_id);
if (it != renderbuffer_infos_.end()) {
- it->second->MarkAsDeleted();
+ RenderbufferInfo* info = it->second;
+ if (!info->cleared()) {
+ --num_uncleared_renderbuffers_;
+ }
+ info->MarkAsDeleted();
renderbuffer_infos_.erase(it);
}
}
diff --git a/gpu/command_buffer/service/renderbuffer_manager.h b/gpu/command_buffer/service/renderbuffer_manager.h
index 619fbf2..5cd7e50 100644
--- a/gpu/command_buffer/service/renderbuffer_manager.h
+++ b/gpu/command_buffer/service/renderbuffer_manager.h
@@ -25,7 +25,7 @@ class RenderbufferManager {
explicit RenderbufferInfo(GLuint service_id)
: service_id_(service_id),
- cleared_(false),
+ cleared_(true),
has_been_bound_(false),
samples_(0),
internal_format_(GL_RGBA4),
@@ -41,10 +41,6 @@ class RenderbufferManager {
return cleared_;
}
- void set_cleared() {
- cleared_ = true;
- }
-
GLenum internal_format() const {
return internal_format_;
}
@@ -61,15 +57,6 @@ class RenderbufferManager {
return height_;
}
- void SetInfo(
- GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
- samples_ = samples;
- internal_format_ = internalformat;
- width_ = width;
- height_ = height;
- cleared_ = false;
- }
-
bool IsDeleted() const {
return service_id_ == 0;
}
@@ -88,6 +75,19 @@ class RenderbufferManager {
~RenderbufferInfo() { }
+ void set_cleared() {
+ cleared_ = true;
+ }
+
+ void SetInfo(
+ GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
+ samples_ = samples;
+ internal_format_ = internalformat;
+ width_ = width;
+ height_ = height;
+ cleared_ = false;
+ }
+
void MarkAsDeleted() {
service_id_ = 0;
}
@@ -123,6 +123,16 @@ class RenderbufferManager {
return max_samples_;
}
+ bool HaveUnclearedRenderbuffers() const {
+ return num_uncleared_renderbuffers_ != 0;
+ }
+
+ void SetInfo(
+ RenderbufferInfo* renderbuffer,
+ GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+
+ void SetCleared(RenderbufferInfo* renderbuffer);
+
// Must call before destruction.
void Destroy(bool have_context);
@@ -142,6 +152,8 @@ class RenderbufferManager {
GLint max_renderbuffer_size_;
GLint max_samples_;
+ int num_uncleared_renderbuffers_;
+
// Info for each renderbuffer in the system.
typedef base::hash_map<GLuint, RenderbufferInfo::Ref> RenderbufferInfoMap;
RenderbufferInfoMap renderbuffer_infos_;
diff --git a/gpu/command_buffer/service/renderbuffer_manager_unittest.cc b/gpu/command_buffer/service/renderbuffer_manager_unittest.cc
index 954778d..63719d7 100644
--- a/gpu/command_buffer/service/renderbuffer_manager_unittest.cc
+++ b/gpu/command_buffer/service/renderbuffer_manager_unittest.cc
@@ -50,12 +50,14 @@ TEST_F(RenderbufferManagerTest, Basic) {
const GLuint kClient2Id = 2;
EXPECT_EQ(kMaxSize, manager_.max_renderbuffer_size());
EXPECT_EQ(kMaxSamples, manager_.max_samples());
+ EXPECT_FALSE(manager_.HaveUnclearedRenderbuffers());
// Check we can create renderbuffer.
manager_.CreateRenderbufferInfo(kClient1Id, kService1Id);
// Check renderbuffer got created.
RenderbufferManager::RenderbufferInfo* info1 =
manager_.GetRenderbufferInfo(kClient1Id);
ASSERT_TRUE(info1 != NULL);
+ EXPECT_FALSE(manager_.HaveUnclearedRenderbuffers());
GLuint client_id = 0;
EXPECT_TRUE(manager_.GetClientId(info1->service_id(), &client_id));
EXPECT_EQ(kClient1Id, client_id);
@@ -66,6 +68,7 @@ TEST_F(RenderbufferManagerTest, Basic) {
// Check we can't get the renderbuffer after we remove it.
manager_.RemoveRenderbufferInfo(kClient1Id);
EXPECT_TRUE(manager_.GetRenderbufferInfo(kClient1Id) == NULL);
+ EXPECT_FALSE(manager_.HaveUnclearedRenderbuffers());
}
TEST_F(RenderbufferManagerTest, Destroy) {
@@ -99,9 +102,6 @@ TEST_F(RenderbufferManagerTest, RenderbufferInfo) {
EXPECT_EQ(static_cast<GLenum>(GL_RGBA4), info1->internal_format());
EXPECT_EQ(0, info1->width());
EXPECT_EQ(0, info1->height());
-
- EXPECT_FALSE(info1->cleared());
- info1->set_cleared();
EXPECT_TRUE(info1->cleared());
// Check if we set the info it gets marked as not cleared.
@@ -109,13 +109,24 @@ TEST_F(RenderbufferManagerTest, RenderbufferInfo) {
const GLenum kFormat = GL_RGBA;
const GLsizei kWidth = 128;
const GLsizei kHeight = 64;
- info1->SetInfo(kSamples, kFormat, kWidth, kHeight);
+ manager_.SetInfo(info1, kSamples, kFormat, kWidth, kHeight);
EXPECT_EQ(kSamples, info1->samples());
EXPECT_EQ(kFormat, info1->internal_format());
EXPECT_EQ(kWidth, info1->width());
EXPECT_EQ(kHeight, info1->height());
EXPECT_FALSE(info1->cleared());
EXPECT_FALSE(info1->IsDeleted());
+ EXPECT_TRUE(manager_.HaveUnclearedRenderbuffers());
+
+ manager_.SetCleared(info1);
+ EXPECT_TRUE(info1->cleared());
+ EXPECT_FALSE(manager_.HaveUnclearedRenderbuffers());
+
+ manager_.SetInfo(info1, kSamples, kFormat, kWidth, kHeight);
+ EXPECT_TRUE(manager_.HaveUnclearedRenderbuffers());
+
+ manager_.RemoveRenderbufferInfo(kClient1Id);
+ EXPECT_FALSE(manager_.HaveUnclearedRenderbuffers());
}
} // namespace gles2
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc
index 329a1f8..e5ace9f 100644
--- a/gpu/command_buffer/service/texture_manager.cc
+++ b/gpu/command_buffer/service/texture_manager.cc
@@ -118,14 +118,15 @@ bool TextureManager::TextureInfo::MarkMipmapsGenerated(
GLsizei width = info1.width;
GLsizei height = info1.height;
GLsizei depth = info1.depth;
+ GLenum target = target_ == GL_TEXTURE_2D ? GL_TEXTURE_2D :
+ FaceIndexToGLTarget(ii);
int num_mips = ComputeMipMapCount(width, height, depth);
for (int level = 1; level < num_mips; ++level) {
width = std::max(1, width >> 1);
height = std::max(1, height >> 1);
depth = std::max(1, depth >> 1);
SetLevelInfo(feature_info,
- target_ == GL_TEXTURE_2D ? GL_TEXTURE_2D :
- FaceIndexToGLTarget(ii),
+ target,
level,
info1.internal_format,
width,
@@ -133,9 +134,11 @@ bool TextureManager::TextureInfo::MarkMipmapsGenerated(
depth,
info1.border,
info1.format,
- info1.type);
+ info1.type,
+ true);
}
}
+
return true;
}
@@ -165,7 +168,7 @@ bool TextureManager::TextureInfo::CanGenerateMipmaps(
// TODO(gman): Check internal_format, format and type.
for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
const LevelInfo& info = level_infos_[ii][0];
- if ((!info.valid) ||
+ if ((info.target == 0) ||
(info.width != first.width) ||
(info.height != first.height) ||
(info.depth != 1) ||
@@ -178,6 +181,43 @@ bool TextureManager::TextureInfo::CanGenerateMipmaps(
return true;
}
+void TextureManager::TextureInfo::SetLevelCleared(GLenum target, GLint level) {
+ DCHECK_GE(level, 0);
+ DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
+ level_infos_.size());
+ DCHECK_LT(static_cast<size_t>(level),
+ level_infos_[GLTargetToFaceIndex(target)].size());
+ TextureInfo::LevelInfo& info =
+ level_infos_[GLTargetToFaceIndex(target)][level];
+ if (!info.cleared) {
+ DCHECK_NE(0, num_uncleared_mips_);
+ --num_uncleared_mips_;
+ }
+ info.cleared = true;
+ UpdateCleared();
+}
+
+void TextureManager::TextureInfo::UpdateCleared() {
+ if (level_infos_.empty()) {
+ return;
+ }
+
+ const TextureInfo::LevelInfo& first_face = level_infos_[0][0];
+ int levels_needed = ComputeMipMapCount(
+ first_face.width, first_face.height, first_face.depth);
+ cleared_ = true;
+ for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
+ for (GLint jj = 0; jj < levels_needed; ++jj) {
+ const TextureInfo::LevelInfo& info = level_infos_[ii][jj];
+ if (info.width > 0 && info.height > 0 && info.depth > 0 &&
+ !info.cleared) {
+ cleared_ = false;
+ return;
+ }
+ }
+ }
+}
+
void TextureManager::TextureInfo::SetLevelInfo(
const FeatureInfo* feature_info,
GLenum target,
@@ -188,7 +228,8 @@ void TextureManager::TextureInfo::SetLevelInfo(
GLsizei depth,
GLint border,
GLenum format,
- GLenum type) {
+ GLenum type,
+ bool cleared) {
DCHECK_GE(level, 0);
DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
level_infos_.size());
@@ -199,7 +240,8 @@ void TextureManager::TextureInfo::SetLevelInfo(
DCHECK_GE(depth, 0);
TextureInfo::LevelInfo& info =
level_infos_[GLTargetToFaceIndex(target)][level];
- info.valid = true;
+ info.target = target;
+ info.level = level;
info.internal_format = internal_format;
info.width = width;
info.height = height;
@@ -207,8 +249,17 @@ void TextureManager::TextureInfo::SetLevelInfo(
info.border = border;
info.format = format;
info.type = type;
+ if (!info.cleared) {
+ DCHECK_NE(0, num_uncleared_mips_);
+ --num_uncleared_mips_;
+ }
+ info.cleared = cleared;
+ if (!info.cleared) {
+ ++num_uncleared_mips_;
+ }
max_level_set_ = std::max(max_level_set_, level);
Update(feature_info);
+ UpdateCleared();
}
bool TextureManager::TextureInfo::ValidForTexture(
@@ -246,7 +297,7 @@ bool TextureManager::TextureInfo::GetLevelSize(
if (!IsDeleted() && level >= 0 && face_index < level_infos_.size() &&
static_cast<size_t>(level) < level_infos_[face_index].size()) {
const LevelInfo& info = level_infos_[GLTargetToFaceIndex(face)][level];
- if (info.valid) {
+ if (info.target != 0) {
*width = info.width;
*height = info.height;
return true;
@@ -263,7 +314,7 @@ bool TextureManager::TextureInfo::GetLevelType(
if (!IsDeleted() && level >= 0 && face_index < level_infos_.size() &&
static_cast<size_t>(level) < level_infos_[face_index].size()) {
const LevelInfo& info = level_infos_[GLTargetToFaceIndex(face)][level];
- if (info.valid) {
+ if (info.target != 0) {
*type = info.type;
*internal_format = info.internal_format;
return true;
@@ -318,6 +369,7 @@ bool TextureManager::TextureInfo::SetParameter(
return false;
}
Update(feature_info);
+ UpdateCleared();
return true;
}
@@ -331,6 +383,7 @@ void TextureManager::TextureInfo::Update(const FeatureInfo* feature_info) {
return;
}
+ // checks that the first mip of any face is npot.
for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
const TextureInfo::LevelInfo& info = level_infos_[ii][0];
if (GLES2Util::IsNPOT(info.width) ||
@@ -367,7 +420,7 @@ void TextureManager::TextureInfo::Update(const FeatureInfo* feature_info) {
ii < level_infos_.size() && (cube_complete_ || texture_complete_);
++ii) {
const TextureInfo::LevelInfo& level0 = level_infos_[ii][0];
- if (!level0.valid ||
+ if (level0.target == 0 ||
level0.width != first_face.width ||
level0.height != first_face.height ||
level0.depth != 1 ||
@@ -386,7 +439,7 @@ void TextureManager::TextureInfo::Update(const FeatureInfo* feature_info) {
height = std::max(1, height >> 1);
depth = std::max(1, depth >> 1);
const TextureInfo::LevelInfo& info = level_infos_[ii][jj];
- if (!info.valid ||
+ if (info.target == 0 ||
info.width != width ||
info.height != height ||
info.depth != depth ||
@@ -400,6 +453,80 @@ void TextureManager::TextureInfo::Update(const FeatureInfo* feature_info) {
}
}
+bool TextureManager::TextureInfo::ClearRenderableLevels(GLES2Decoder* decoder) {
+ DCHECK(decoder);
+ if (SafeToRenderFrom()) {
+ return true;
+ }
+
+ const TextureInfo::LevelInfo& first_face = level_infos_[0][0];
+ int levels_needed = ComputeMipMapCount(
+ first_face.width, first_face.height, first_face.depth);
+
+ for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
+ for (GLint jj = 0; jj < levels_needed; ++jj) {
+ TextureInfo::LevelInfo& info = level_infos_[ii][jj];
+ if (info.target != 0) {
+ if (!ClearLevel(decoder, info.target, jj)) {
+ return false;
+ }
+ }
+ }
+ }
+ cleared_ = true;
+ return true;
+}
+
+bool TextureManager::TextureInfo::IsLevelCleared(GLenum target, GLint level) {
+ size_t face_index = GLTargetToFaceIndex(target);
+ if (IsDeleted() ||
+ face_index >= level_infos_.size() ||
+ level >= static_cast<GLint>(level_infos_[face_index].size())) {
+ return true;
+ }
+
+ TextureInfo::LevelInfo& info = level_infos_[face_index][level];
+
+ return info.cleared;
+}
+
+bool TextureManager::TextureInfo::ClearLevel(
+ GLES2Decoder* decoder, GLenum target, GLint level) {
+ DCHECK(decoder);
+ size_t face_index = GLTargetToFaceIndex(target);
+ if (IsDeleted() ||
+ face_index >= level_infos_.size() ||
+ level >= static_cast<GLint>(level_infos_[face_index].size())) {
+ return true;
+ }
+
+ TextureInfo::LevelInfo& info = level_infos_[face_index][level];
+
+ DCHECK(target == info.target);
+
+ if (info.target == 0 ||
+ info.cleared ||
+ info.width == 0 ||
+ info.height == 0 ||
+ info.depth == 0) {
+ return true;
+ }
+
+ DCHECK_NE(0, num_uncleared_mips_);
+ --num_uncleared_mips_;
+
+ // NOTE: It seems kind of gross to call back into the decoder for this
+ // but only the decoder knows all the state (like unpack_alignment_) that's
+ // needed to be able to call GL correctly.
+ info.cleared = decoder->ClearLevel(
+ service_id_, target_, info.target, info.level, info.format, info.type,
+ info.width, info.height);
+ if (!info.cleared) {
+ ++num_uncleared_mips_;
+ }
+ return info.cleared;
+}
+
TextureManager::TextureManager(
GLint max_texture_size,
GLint max_cube_map_texture_size)
@@ -412,6 +539,8 @@ TextureManager::TextureManager(
max_cube_map_texture_size,
max_cube_map_texture_size)),
num_unrenderable_textures_(0),
+ num_unsafe_textures_(0),
+ num_uncleared_mips_(0),
black_2d_texture_id_(0),
black_cube_texture_id_(0) {
}
@@ -439,23 +568,30 @@ bool TextureManager::Initialize(const FeatureInfo* feature_info) {
glBindTexture(GL_TEXTURE_2D, 0);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+ // Since we are manually setting up these textures
+ // we need to manually manipulate some of the their bookkeeping.
+ num_unrenderable_textures_ += 2;
FeatureInfo temp_feature_info;
default_texture_2d_ = TextureInfo::Ref(new TextureInfo(ids[1]));
SetInfoTarget(feature_info, default_texture_2d_, GL_TEXTURE_2D);
- default_texture_2d_->SetLevelInfo(&temp_feature_info,
- GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ SetLevelInfo(&temp_feature_info, default_texture_2d_,
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
default_texture_cube_map_ = TextureInfo::Ref(new TextureInfo(ids[3]));
SetInfoTarget(feature_info, default_texture_cube_map_, GL_TEXTURE_CUBE_MAP);
for (int ii = 0; ii < GLES2Util::kNumFaces; ++ii) {
- default_texture_cube_map_->SetLevelInfo(
- &temp_feature_info, GLES2Util::IndexToGLFaceTarget(ii),
- 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ SetLevelInfo(
+ &temp_feature_info, default_texture_cube_map_,
+ GLES2Util::IndexToGLFaceTarget(ii),
+ 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
}
black_2d_texture_id_ = ids[0];
black_cube_texture_id_ = ids[2];
if (feature_info->feature_flags().oes_egl_image_external) {
+ // Since we are manually setting up these textures
+ // we need to manually manipulate some of the their bookkeeping.
+ num_unrenderable_textures_ += 1;
GLuint external_ids[2];
glGenTextures(arraysize(external_ids), external_ids);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
@@ -466,7 +602,7 @@ bool TextureManager::Initialize(const FeatureInfo* feature_info) {
GL_TEXTURE_EXTERNAL_OES);
default_texture_external_oes_->SetLevelInfo(
&temp_feature_info, GL_TEXTURE_EXTERNAL_OES, 0,
- GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
// Sampling a texture not associated with any EGLImage sibling will return
// black values according to the spec.
@@ -499,9 +635,10 @@ bool TextureManager::ValidForTarget(
void TextureManager::SetInfoTarget(
const FeatureInfo* feature_info,
- TextureInfo* info, GLenum target) {
+ TextureManager::TextureInfo* info, GLenum target) {
DCHECK(info);
if (!info->CanRender(feature_info)) {
+ DCHECK_NE(0, num_unrenderable_textures_);
--num_unrenderable_textures_;
}
info->SetTarget(target, MaxLevelsForTarget(target));
@@ -510,6 +647,65 @@ void TextureManager::SetInfoTarget(
}
}
+void TextureManager::SetLevelCleared(
+ TextureManager::TextureInfo* info, GLenum target, GLint level) {
+ DCHECK(info);
+ DCHECK(!info->IsDeleted());
+ if (!info->SafeToRenderFrom()) {
+ DCHECK_NE(0, num_unsafe_textures_);
+ --num_unsafe_textures_;
+ }
+ num_uncleared_mips_ -= info->num_uncleared_mips();
+ DCHECK_GE(num_uncleared_mips_, 0);
+ info->SetLevelCleared(target, level);
+ num_uncleared_mips_ += info->num_uncleared_mips();
+ if (!info->SafeToRenderFrom()) {
+ ++num_unsafe_textures_;
+ }
+}
+
+bool TextureManager::ClearRenderableLevels(
+ GLES2Decoder* decoder,TextureManager::TextureInfo* info) {
+ DCHECK(info);
+ DCHECK(!info->IsDeleted());
+ if (info->SafeToRenderFrom()) {
+ return true;
+ }
+ DCHECK_NE(0, num_unsafe_textures_);
+ --num_unsafe_textures_;
+ num_uncleared_mips_ -= info->num_uncleared_mips();
+ DCHECK_GE(num_uncleared_mips_, 0);
+ bool result = info->ClearRenderableLevels(decoder);
+ num_uncleared_mips_ += info->num_uncleared_mips();
+ if (!info->SafeToRenderFrom()) {
+ ++num_unsafe_textures_;
+ }
+ return result;
+}
+
+bool TextureManager::ClearTextureLevel(
+ GLES2Decoder* decoder,TextureManager::TextureInfo* info,
+ GLenum target, GLint level) {
+ DCHECK(info);
+ DCHECK(!info->IsDeleted());
+ if (info->num_uncleared_mips() == 0) {
+ return true;
+ }
+ num_uncleared_mips_ -= info->num_uncleared_mips();
+ DCHECK_GE(num_uncleared_mips_, 0);
+ if (!info->SafeToRenderFrom()) {
+ DCHECK_NE(0, num_unsafe_textures_);
+ --num_unsafe_textures_;
+ }
+ bool result = info->ClearLevel(decoder, target, level);
+ info->UpdateCleared();
+ num_uncleared_mips_ += info->num_uncleared_mips();
+ if (!info->SafeToRenderFrom()) {
+ ++num_unsafe_textures_;
+ }
+ return result;
+}
+
void TextureManager::SetLevelInfo(
const FeatureInfo* feature_info,
TextureManager::TextureInfo* info,
@@ -521,18 +717,30 @@ void TextureManager::SetLevelInfo(
GLsizei depth,
GLint border,
GLenum format,
- GLenum type) {
+ GLenum type,
+ bool cleared) {
DCHECK(info);
DCHECK(!info->IsDeleted());
if (!info->CanRender(feature_info)) {
+ DCHECK_NE(0, num_unrenderable_textures_);
--num_unrenderable_textures_;
}
+ if (!info->SafeToRenderFrom()) {
+ DCHECK_NE(0, num_unsafe_textures_);
+ --num_unsafe_textures_;
+ }
+ num_uncleared_mips_ -= info->num_uncleared_mips();
+ DCHECK_GE(num_uncleared_mips_, 0);
info->SetLevelInfo(
feature_info, target, level, internal_format, width, height, depth,
- border, format, type);
+ border, format, type, cleared);
+ num_uncleared_mips_ += info->num_uncleared_mips();
if (!info->CanRender(feature_info)) {
++num_unrenderable_textures_;
}
+ if (!info->SafeToRenderFrom()) {
+ ++num_unsafe_textures_;
+ }
}
bool TextureManager::SetParameter(
@@ -542,12 +750,20 @@ bool TextureManager::SetParameter(
DCHECK(info);
DCHECK(!info->IsDeleted());
if (!info->CanRender(feature_info)) {
+ DCHECK_NE(0, num_unrenderable_textures_);
--num_unrenderable_textures_;
}
+ if (!info->SafeToRenderFrom()) {
+ DCHECK_NE(0, num_unsafe_textures_);
+ --num_unsafe_textures_;
+ }
bool result = info->SetParameter(feature_info, pname, param);
if (!info->CanRender(feature_info)) {
++num_unrenderable_textures_;
}
+ if (!info->SafeToRenderFrom()) {
+ ++num_unsafe_textures_;
+ }
return result;
}
@@ -557,12 +773,23 @@ bool TextureManager::MarkMipmapsGenerated(
DCHECK(info);
DCHECK(!info->IsDeleted());
if (!info->CanRender(feature_info)) {
+ DCHECK_NE(0, num_unrenderable_textures_);
--num_unrenderable_textures_;
}
+ if (!info->SafeToRenderFrom()) {
+ DCHECK_NE(0, num_unsafe_textures_);
+ --num_unsafe_textures_;
+ }
+ num_uncleared_mips_ -= info->num_uncleared_mips();
+ DCHECK_GE(num_uncleared_mips_, 0);
bool result = info->MarkMipmapsGenerated(feature_info);
+ num_uncleared_mips_ += info->num_uncleared_mips();
if (!info->CanRender(feature_info)) {
++num_unrenderable_textures_;
}
+ if (!info->SafeToRenderFrom()) {
+ ++num_unsafe_textures_;
+ }
return result;
}
@@ -576,6 +803,10 @@ TextureManager::TextureInfo* TextureManager::CreateTextureInfo(
if (!info->CanRender(feature_info)) {
++num_unrenderable_textures_;
}
+ if (!info->SafeToRenderFrom()) {
+ ++num_unsafe_textures_;
+ }
+ num_uncleared_mips_ += info->num_uncleared_mips();
return info.get();
}
@@ -591,8 +822,15 @@ void TextureManager::RemoveTextureInfo(
if (it != texture_infos_.end()) {
TextureInfo* info = it->second;
if (!info->CanRender(feature_info)) {
+ DCHECK_NE(0, num_unrenderable_textures_);
--num_unrenderable_textures_;
}
+ if (!info->SafeToRenderFrom()) {
+ DCHECK_NE(0, num_unsafe_textures_);
+ --num_unsafe_textures_;
+ }
+ num_uncleared_mips_ -= info->num_uncleared_mips();
+ DCHECK_GE(num_uncleared_mips_, 0);
info->MarkAsDeleted();
texture_infos_.erase(it);
}
diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h
index dbb2218..0fccbf6 100644
--- a/gpu/command_buffer/service/texture_manager.h
+++ b/gpu/command_buffer/service/texture_manager.h
@@ -16,6 +16,7 @@ namespace gpu {
namespace gles2 {
class FeatureInfo;
+class GLES2Decoder;
// This class keeps track of the textures and their sizes so we can do NPOT and
// texture complete checking.
@@ -32,6 +33,8 @@ class TextureManager {
explicit TextureInfo(GLuint service_id)
: service_id_(service_id),
deleted_(false),
+ cleared_(true),
+ num_uncleared_mips_(0),
target_(0),
min_filter_(GL_NEAREST_MIPMAP_LINEAR),
mag_filter_(GL_LINEAR),
@@ -63,6 +66,10 @@ class TextureManager {
return wrap_t_;
}
+ int num_uncleared_mips() const {
+ return num_uncleared_mips_;
+ }
+
// True if this texture meets all the GLES2 criteria for rendering.
// See section 3.8.2 of the GLES2 spec.
bool CanRender(const FeatureInfo* feature_info) const;
@@ -101,6 +108,10 @@ class TextureManager {
return npot_;
}
+ bool SafeToRenderFrom() const {
+ return cleared_;
+ }
+
// Returns true if mipmaps can be generated by GL.
bool CanGenerateMipmaps(const FeatureInfo* feature_info) const;
@@ -146,7 +157,7 @@ class TextureManager {
}
void DetachFromFramebuffer() {
- DCHECK(framebuffer_attachment_count_ > 0);
+ DCHECK_GT(framebuffer_attachment_count_, 0);
--framebuffer_attachment_count_;
}
@@ -158,6 +169,9 @@ class TextureManager {
return stream_texture_;
}
+ // Whether a particular level/face is cleared.
+ bool IsLevelCleared(GLenum target, GLint level);
+
private:
friend class TextureManager;
friend class base::RefCounted<TextureInfo>;
@@ -166,7 +180,9 @@ class TextureManager {
struct LevelInfo {
LevelInfo()
- : valid(false),
+ : cleared(true),
+ target(0),
+ level(-1),
internal_format(0),
width(0),
height(0),
@@ -176,7 +192,9 @@ class TextureManager {
type(0) {
}
- bool valid;
+ bool cleared;
+ GLenum target;
+ GLint level;
GLenum internal_format;
GLsizei width;
GLsizei height;
@@ -197,7 +215,22 @@ class TextureManager {
GLsizei depth,
GLint border,
GLenum format,
- GLenum type);
+ GLenum type,
+ bool cleared);
+
+ // Marks a particular level as cleared or uncleared.
+ void SetLevelCleared(GLenum target, GLint level);
+
+ // Updates the cleared flag for this texture by inspecting all the mips.
+ void UpdateCleared();
+
+ // Clears any renderable uncleared levels.
+ // Returns false if a GL error was generated.
+ bool ClearRenderableLevels(GLES2Decoder* decoder);
+
+ // Clears the level.
+ // Returns false if a GL error was generated.
+ bool ClearLevel(GLES2Decoder* decoder, GLenum target, GLint level);
// Sets a texture parameter.
// TODO(gman): Expand to SetParameteri,f,iv,fv
@@ -236,6 +269,11 @@ class TextureManager {
// Whether this texture has been deleted.
bool deleted_;
+ // Whether all renderable mips of this texture have been cleared.
+ bool cleared_;
+
+ int num_uncleared_mips_;
+
// The target. 0 if unset, otherwise GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP.
GLenum target_;
@@ -333,7 +371,11 @@ class TextureManager {
GLsizei depth,
GLint border,
GLenum format,
- GLenum type);
+ GLenum type,
+ bool cleared);
+
+ // Sets a mip as cleared.
+ void SetLevelCleared(TextureInfo* info, GLenum target, GLint level);
// Sets a texture parameter of a TextureInfo
// TODO(gman): Expand to SetParameteri,f,iv,fv
@@ -343,9 +385,14 @@ class TextureManager {
// Makes each of the mip levels as though they were generated.
// Returns false if that's not allowed for the given texture.
- bool MarkMipmapsGenerated(
- const FeatureInfo* feature_info,
- TextureManager::TextureInfo* info);
+ bool MarkMipmapsGenerated(const FeatureInfo* feature_info, TextureInfo* info);
+
+ // Clears any uncleared renderable levels.
+ bool ClearRenderableLevels(GLES2Decoder* decoder, TextureInfo* info);
+
+ // Clear a specific level.
+ bool ClearTextureLevel(
+ GLES2Decoder* decoder,TextureInfo* info, GLenum target, GLint level);
// Creates a new texture info.
TextureInfo* CreateTextureInfo(
@@ -378,6 +425,14 @@ class TextureManager {
return num_unrenderable_textures_ > 0;
}
+ bool HaveUnsafeTextures() const {
+ return num_unsafe_textures_ > 0;
+ }
+
+ bool HaveUnclearedMips() const {
+ return num_uncleared_mips_ > 0;
+ }
+
GLuint black_texture_id(GLenum target) const {
switch (target) {
case GL_SAMPLER_2D:
@@ -403,6 +458,8 @@ class TextureManager {
GLint max_cube_map_levels_;
int num_unrenderable_textures_;
+ int num_unsafe_textures_;
+ int num_uncleared_mips_;
// Black (0,0,0,1) textures for when non-renderable textures are used.
// NOTE: There is no corresponding TextureInfo for these textures.
diff --git a/gpu/command_buffer/service/texture_manager_unittest.cc b/gpu/command_buffer/service/texture_manager_unittest.cc
index 38d1969..44ce830 100644
--- a/gpu/command_buffer/service/texture_manager_unittest.cc
+++ b/gpu/command_buffer/service/texture_manager_unittest.cc
@@ -7,10 +7,12 @@
#include "base/memory/scoped_ptr.h"
#include "gpu/command_buffer/common/gl_mock.h"
#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
#include "gpu/command_buffer/service/test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::Pointee;
+using ::testing::Return;
using ::testing::_;
namespace gpu {
@@ -78,6 +80,8 @@ TEST_F(TextureManagerTest, Basic) {
const GLuint kService1Id = 11;
const GLuint kClient2Id = 2;
EXPECT_FALSE(manager_.HaveUnrenderableTextures());
+ EXPECT_FALSE(manager_.HaveUnsafeTextures());
+ EXPECT_FALSE(manager_.HaveUnclearedMips());
// Check we can create texture.
manager_.CreateTextureInfo(&feature_info_, kClient1Id, kService1Id);
// Check texture got created.
@@ -99,7 +103,6 @@ TEST_F(TextureManagerTest, Basic) {
TEST_F(TextureManagerTest, SetParameter) {
const GLuint kClient1Id = 1;
const GLuint kService1Id = 11;
- EXPECT_FALSE(manager_.HaveUnrenderableTextures());
// Check we can create texture.
manager_.CreateTextureInfo(&feature_info_, kClient1Id, kService1Id);
// Check texture got created.
@@ -134,7 +137,6 @@ TEST_F(TextureManagerTest, SetParameter) {
TEST_F(TextureManagerTest, Destroy) {
const GLuint kClient1Id = 1;
const GLuint kService1Id = 11;
- EXPECT_FALSE(manager_.HaveUnrenderableTextures());
// Check we can create texture.
manager_.CreateTextureInfo(&feature_info_, kClient1Id, kService1Id);
// Check texture got created.
@@ -155,7 +157,6 @@ TEST_F(TextureManagerTest, Destroy) {
TEST_F(TextureManagerTest, DestroyUnowned) {
const GLuint kClient1Id = 1;
const GLuint kService1Id = 11;
- EXPECT_FALSE(manager_.HaveUnrenderableTextures());
// Check we can create texture.
TextureManager::TextureInfo* created_info =
manager_.CreateTextureInfo(&feature_info_, kClient1Id, kService1Id);
@@ -329,12 +330,15 @@ TEST_F(TextureInfoTest, Basic) {
EXPECT_FALSE(info_->cube_complete());
EXPECT_FALSE(info_->CanGenerateMipmaps(&feature_info_));
EXPECT_FALSE(info_->npot());
+ EXPECT_EQ(0, info_->num_uncleared_mips());
EXPECT_FALSE(info_->CanRender(&feature_info_));
+ EXPECT_TRUE(info_->SafeToRenderFrom());
EXPECT_EQ(static_cast<GLenum>(GL_NEAREST_MIPMAP_LINEAR), info_->min_filter());
EXPECT_EQ(static_cast<GLenum>(GL_LINEAR), info_->mag_filter());
EXPECT_EQ(static_cast<GLenum>(GL_REPEAT), info_->wrap_s());
EXPECT_EQ(static_cast<GLenum>(GL_REPEAT), info_->wrap_t());
EXPECT_TRUE(manager_.HaveUnrenderableTextures());
+ EXPECT_FALSE(manager_.HaveUnsafeTextures());
}
TEST_F(TextureInfoTest, POT2D) {
@@ -342,10 +346,11 @@ TEST_F(TextureInfoTest, POT2D) {
EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), info_->target());
// Check Setting level 0 to POT
manager_.SetLevelInfo(&feature_info_, info_,
- GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
EXPECT_FALSE(info_->npot());
EXPECT_FALSE(info_->texture_complete());
EXPECT_FALSE(info_->CanRender(&feature_info_));
+ EXPECT_EQ(0, info_->num_uncleared_mips());
EXPECT_TRUE(manager_.HaveUnrenderableTextures());
// Set filters to something that will work with a single mip.
manager_.SetParameter(
@@ -365,7 +370,7 @@ TEST_F(TextureInfoTest, POT2D) {
EXPECT_FALSE(manager_.HaveUnrenderableTextures());
// Change a mip.
manager_.SetLevelInfo(&feature_info_, info_,
- GL_TEXTURE_2D, 1, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ GL_TEXTURE_2D, 1, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
EXPECT_FALSE(info_->npot());
EXPECT_FALSE(info_->texture_complete());
EXPECT_TRUE(info_->CanGenerateMipmaps(&feature_info_));
@@ -373,7 +378,7 @@ TEST_F(TextureInfoTest, POT2D) {
EXPECT_TRUE(manager_.HaveUnrenderableTextures());
// Set a level past the number of mips that would get generated.
manager_.SetLevelInfo(&feature_info_, info_,
- GL_TEXTURE_2D, 3, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ GL_TEXTURE_2D, 3, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
EXPECT_TRUE(info_->CanGenerateMipmaps(&feature_info_));
// Make mips.
EXPECT_TRUE(manager_.MarkMipmapsGenerated(&feature_info_, info_));
@@ -387,7 +392,7 @@ TEST_F(TextureInfoTest, UnusedMips) {
EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), info_->target());
// Set level zero to large size.
manager_.SetLevelInfo(&feature_info_, info_,
- GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
EXPECT_TRUE(manager_.MarkMipmapsGenerated(&feature_info_, info_));
EXPECT_FALSE(info_->npot());
EXPECT_TRUE(info_->texture_complete());
@@ -395,7 +400,7 @@ TEST_F(TextureInfoTest, UnusedMips) {
EXPECT_FALSE(manager_.HaveUnrenderableTextures());
// Set level zero to large smaller (levels unused mips)
manager_.SetLevelInfo(&feature_info_, info_,
- GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
EXPECT_TRUE(manager_.MarkMipmapsGenerated(&feature_info_, info_));
EXPECT_FALSE(info_->npot());
EXPECT_TRUE(info_->texture_complete());
@@ -403,7 +408,7 @@ TEST_F(TextureInfoTest, UnusedMips) {
EXPECT_FALSE(manager_.HaveUnrenderableTextures());
// Set an unused level to some size
manager_.SetLevelInfo(&feature_info_, info_,
- GL_TEXTURE_2D, 4, GL_RGBA, 16, 16, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ GL_TEXTURE_2D, 4, GL_RGBA, 16, 16, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
EXPECT_FALSE(info_->npot());
EXPECT_TRUE(info_->texture_complete());
EXPECT_TRUE(info_->CanRender(&feature_info_));
@@ -415,7 +420,7 @@ TEST_F(TextureInfoTest, NPOT2D) {
EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), info_->target());
// Check Setting level 0 to NPOT
manager_.SetLevelInfo(&feature_info_, info_,
- GL_TEXTURE_2D, 0, GL_RGBA, 4, 5, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ GL_TEXTURE_2D, 0, GL_RGBA, 4, 5, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
EXPECT_TRUE(info_->npot());
EXPECT_FALSE(info_->texture_complete());
EXPECT_FALSE(info_->CanGenerateMipmaps(&feature_info_));
@@ -435,7 +440,7 @@ TEST_F(TextureInfoTest, NPOT2D) {
EXPECT_FALSE(manager_.HaveUnrenderableTextures());
// Change it to POT.
manager_.SetLevelInfo(&feature_info_, info_,
- GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
EXPECT_FALSE(info_->npot());
EXPECT_FALSE(info_->texture_complete());
EXPECT_TRUE(info_->CanGenerateMipmaps(&feature_info_));
@@ -456,7 +461,7 @@ TEST_F(TextureInfoTest, NPOT2DNPOTOK) {
EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), info->target());
// Check Setting level 0 to NPOT
manager.SetLevelInfo(&feature_info, info,
- GL_TEXTURE_2D, 0, GL_RGBA, 4, 5, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ GL_TEXTURE_2D, 0, GL_RGBA, 4, 5, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
EXPECT_TRUE(info->npot());
EXPECT_FALSE(info->texture_complete());
EXPECT_TRUE(info->CanGenerateMipmaps(&feature_info));
@@ -475,7 +480,7 @@ TEST_F(TextureInfoTest, POTCubeMap) {
// Check Setting level 0 each face to POT
manager_.SetLevelInfo(&feature_info_, info_,
GL_TEXTURE_CUBE_MAP_POSITIVE_X,
- 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
EXPECT_FALSE(info_->npot());
EXPECT_FALSE(info_->texture_complete());
EXPECT_FALSE(info_->cube_complete());
@@ -484,7 +489,7 @@ TEST_F(TextureInfoTest, POTCubeMap) {
EXPECT_TRUE(manager_.HaveUnrenderableTextures());
manager_.SetLevelInfo(&feature_info_, info_,
GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
- 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
EXPECT_FALSE(info_->npot());
EXPECT_FALSE(info_->texture_complete());
EXPECT_FALSE(info_->cube_complete());
@@ -493,7 +498,7 @@ TEST_F(TextureInfoTest, POTCubeMap) {
EXPECT_TRUE(manager_.HaveUnrenderableTextures());
manager_.SetLevelInfo(&feature_info_, info_,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
- 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
EXPECT_FALSE(info_->npot());
EXPECT_FALSE(info_->texture_complete());
EXPECT_FALSE(info_->cube_complete());
@@ -502,7 +507,7 @@ TEST_F(TextureInfoTest, POTCubeMap) {
EXPECT_TRUE(manager_.HaveUnrenderableTextures());
manager_.SetLevelInfo(&feature_info_, info_,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
- 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
EXPECT_FALSE(info_->npot());
EXPECT_FALSE(info_->texture_complete());
EXPECT_FALSE(info_->cube_complete());
@@ -511,7 +516,7 @@ TEST_F(TextureInfoTest, POTCubeMap) {
EXPECT_TRUE(manager_.HaveUnrenderableTextures());
manager_.SetLevelInfo(&feature_info_, info_,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
- 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
EXPECT_FALSE(info_->npot());
EXPECT_FALSE(info_->texture_complete());
EXPECT_FALSE(info_->cube_complete());
@@ -520,7 +525,7 @@ TEST_F(TextureInfoTest, POTCubeMap) {
EXPECT_TRUE(manager_.HaveUnrenderableTextures());
manager_.SetLevelInfo(&feature_info_, info_,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
- 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
EXPECT_FALSE(info_->npot());
EXPECT_FALSE(info_->texture_complete());
EXPECT_TRUE(info_->cube_complete());
@@ -538,7 +543,7 @@ TEST_F(TextureInfoTest, POTCubeMap) {
// Change a mip.
manager_.SetLevelInfo(&feature_info_, info_,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
- 1, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ 1, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
EXPECT_FALSE(info_->npot());
EXPECT_FALSE(info_->texture_complete());
EXPECT_TRUE(info_->cube_complete());
@@ -546,7 +551,7 @@ TEST_F(TextureInfoTest, POTCubeMap) {
// Set a level past the number of mips that would get generated.
manager_.SetLevelInfo(&feature_info_, info_,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
- 3, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ 3, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
EXPECT_TRUE(info_->CanGenerateMipmaps(&feature_info_));
// Make mips.
EXPECT_TRUE(manager_.MarkMipmapsGenerated(&feature_info_, info_));
@@ -557,7 +562,7 @@ TEST_F(TextureInfoTest, POTCubeMap) {
TEST_F(TextureInfoTest, GetLevelSize) {
manager_.SetInfoTarget(&feature_info_, info_, GL_TEXTURE_2D);
manager_.SetLevelInfo(&feature_info_, info_,
- GL_TEXTURE_2D, 1, GL_RGBA, 4, 5, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ GL_TEXTURE_2D, 1, GL_RGBA, 4, 5, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
GLsizei width = -1;
GLsizei height = -1;
EXPECT_FALSE(info_->GetLevelSize(GL_TEXTURE_2D, -1, &width, &height));
@@ -573,7 +578,7 @@ TEST_F(TextureInfoTest, GetLevelSize) {
TEST_F(TextureInfoTest, GetLevelType) {
manager_.SetInfoTarget(&feature_info_, info_, GL_TEXTURE_2D);
manager_.SetLevelInfo(&feature_info_, info_,
- GL_TEXTURE_2D, 1, GL_RGBA, 4, 5, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ GL_TEXTURE_2D, 1, GL_RGBA, 4, 5, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
GLenum type = -1;
GLenum format = -1;
EXPECT_FALSE(info_->GetLevelType(GL_TEXTURE_2D, -1, &type, &format));
@@ -589,7 +594,7 @@ TEST_F(TextureInfoTest, GetLevelType) {
TEST_F(TextureInfoTest, ValidForTexture) {
manager_.SetInfoTarget(&feature_info_, info_, GL_TEXTURE_2D);
manager_.SetLevelInfo(&feature_info_, info_,
- GL_TEXTURE_2D, 1, GL_RGBA, 4, 5, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+ GL_TEXTURE_2D, 1, GL_RGBA, 4, 5, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
// Check bad face.
EXPECT_FALSE(info_->ValidForTexture(
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
@@ -644,7 +649,7 @@ TEST_F(TextureInfoTest, FloatNotLinear) {
manager.SetInfoTarget(&feature_info_, info, GL_TEXTURE_2D);
EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), info->target());
manager.SetLevelInfo(&feature_info, info,
- GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_FLOAT);
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_FLOAT, true);
EXPECT_FALSE(info->texture_complete());
manager.SetParameter(&feature_info, info, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
EXPECT_FALSE(info->texture_complete());
@@ -666,7 +671,7 @@ TEST_F(TextureInfoTest, FloatLinear) {
manager.SetInfoTarget(&feature_info_, info, GL_TEXTURE_2D);
EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), info->target());
manager.SetLevelInfo(&feature_info, info,
- GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_FLOAT);
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_FLOAT, true);
EXPECT_TRUE(info->texture_complete());
manager.Destroy(false);
}
@@ -683,7 +688,7 @@ TEST_F(TextureInfoTest, HalfFloatNotLinear) {
manager.SetInfoTarget(&feature_info_, info, GL_TEXTURE_2D);
EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), info->target());
manager.SetLevelInfo(&feature_info, info,
- GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_HALF_FLOAT_OES);
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_HALF_FLOAT_OES, true);
EXPECT_FALSE(info->texture_complete());
manager.SetParameter(&feature_info, info, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
EXPECT_FALSE(info->texture_complete());
@@ -705,7 +710,7 @@ TEST_F(TextureInfoTest, HalfFloatLinear) {
manager.SetInfoTarget(&feature_info_, info, GL_TEXTURE_2D);
EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), info->target());
manager.SetLevelInfo(&feature_info, info,
- GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_HALF_FLOAT_OES);
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_HALF_FLOAT_OES, true);
EXPECT_TRUE(info->texture_complete());
manager.Destroy(false);
}
@@ -725,6 +730,156 @@ TEST_F(TextureInfoTest, EGLImageExternal) {
manager.Destroy(false);
}
+TEST_F(TextureInfoTest, SafeUnsafe) {
+ static const GLuint kClient2Id = 2;
+ static const GLuint kService2Id = 12;
+ static const GLuint kClient3Id = 3;
+ static const GLuint kService3Id = 13;
+ EXPECT_FALSE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(0, info_->num_uncleared_mips());
+ manager_.SetInfoTarget(&feature_info_, info_, GL_TEXTURE_2D);
+ manager_.SetLevelInfo(&feature_info_, info_,
+ GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, false);
+ EXPECT_FALSE(info_->SafeToRenderFrom());
+ EXPECT_TRUE(manager_.HaveUnsafeTextures());
+ EXPECT_TRUE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(1, info_->num_uncleared_mips());
+ manager_.SetLevelCleared(info_, GL_TEXTURE_2D, 0);
+ EXPECT_TRUE(info_->SafeToRenderFrom());
+ EXPECT_FALSE(manager_.HaveUnsafeTextures());
+ EXPECT_FALSE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(0, info_->num_uncleared_mips());
+ manager_.SetLevelInfo(&feature_info_, info_,
+ GL_TEXTURE_2D, 1, GL_RGBA, 8, 8, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, false);
+ EXPECT_FALSE(info_->SafeToRenderFrom());
+ EXPECT_TRUE(manager_.HaveUnsafeTextures());
+ EXPECT_TRUE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(1, info_->num_uncleared_mips());
+ manager_.SetLevelCleared(info_, GL_TEXTURE_2D, 1);
+ EXPECT_TRUE(info_->SafeToRenderFrom());
+ EXPECT_FALSE(manager_.HaveUnsafeTextures());
+ EXPECT_FALSE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(0, info_->num_uncleared_mips());
+ manager_.SetLevelInfo(&feature_info_, info_,
+ GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, false);
+ manager_.SetLevelInfo(&feature_info_, info_,
+ GL_TEXTURE_2D, 1, GL_RGBA, 8, 8, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, false);
+ EXPECT_FALSE(info_->SafeToRenderFrom());
+ EXPECT_TRUE(manager_.HaveUnsafeTextures());
+ EXPECT_TRUE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(2, info_->num_uncleared_mips());
+ manager_.SetLevelCleared(info_, GL_TEXTURE_2D, 0);
+ EXPECT_FALSE(info_->SafeToRenderFrom());
+ EXPECT_TRUE(manager_.HaveUnsafeTextures());
+ EXPECT_TRUE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(1, info_->num_uncleared_mips());
+ manager_.SetLevelCleared(info_, GL_TEXTURE_2D, 1);
+ EXPECT_TRUE(info_->SafeToRenderFrom());
+ EXPECT_FALSE(manager_.HaveUnsafeTextures());
+ EXPECT_FALSE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(0, info_->num_uncleared_mips());
+ manager_.SetLevelInfo(&feature_info_, info_,
+ GL_TEXTURE_2D, 1, GL_RGBA, 8, 8, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, false);
+ EXPECT_FALSE(info_->SafeToRenderFrom());
+ EXPECT_TRUE(manager_.HaveUnsafeTextures());
+ EXPECT_TRUE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(1, info_->num_uncleared_mips());
+ manager_.MarkMipmapsGenerated(&feature_info_, info_);
+ EXPECT_TRUE(info_->SafeToRenderFrom());
+ EXPECT_FALSE(manager_.HaveUnsafeTextures());
+ EXPECT_FALSE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(0, info_->num_uncleared_mips());
+
+ manager_.CreateTextureInfo(&feature_info_, kClient2Id, kService2Id);
+ TextureManager::TextureInfo::Ref info2 = manager_.GetTextureInfo(kClient2Id);
+ ASSERT_TRUE(info2.get() != NULL);
+ manager_.SetInfoTarget(&feature_info_, info2, GL_TEXTURE_2D);
+ EXPECT_FALSE(manager_.HaveUnsafeTextures());
+ EXPECT_FALSE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(0, info2->num_uncleared_mips());
+ manager_.SetLevelInfo(&feature_info_, info2,
+ GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
+ EXPECT_FALSE(manager_.HaveUnsafeTextures());
+ EXPECT_FALSE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(0, info2->num_uncleared_mips());
+ manager_.SetLevelInfo(&feature_info_, info2,
+ GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, false);
+ EXPECT_TRUE(manager_.HaveUnsafeTextures());
+ EXPECT_TRUE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(1, info2->num_uncleared_mips());
+
+ manager_.CreateTextureInfo(&feature_info_, kClient3Id, kService3Id);
+ TextureManager::TextureInfo::Ref info3 = manager_.GetTextureInfo(kClient3Id);
+ ASSERT_TRUE(info3.get() != NULL);
+ manager_.SetInfoTarget(&feature_info_, info3, GL_TEXTURE_2D);
+ manager_.SetLevelInfo(&feature_info_, info3,
+ GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, false);
+ EXPECT_TRUE(manager_.HaveUnsafeTextures());
+ EXPECT_TRUE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(1, info3->num_uncleared_mips());
+ manager_.SetLevelCleared(info2, GL_TEXTURE_2D, 0);
+ EXPECT_TRUE(manager_.HaveUnsafeTextures());
+ EXPECT_TRUE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(0, info2->num_uncleared_mips());
+ manager_.SetLevelCleared(info3, GL_TEXTURE_2D, 0);
+ EXPECT_FALSE(manager_.HaveUnsafeTextures());
+ EXPECT_FALSE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(0, info3->num_uncleared_mips());
+
+ manager_.SetLevelInfo(&feature_info_, info2,
+ GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, false);
+ manager_.SetLevelInfo(&feature_info_, info3,
+ GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, false);
+ EXPECT_TRUE(manager_.HaveUnsafeTextures());
+ EXPECT_TRUE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(1, info2->num_uncleared_mips());
+ EXPECT_EQ(1, info3->num_uncleared_mips());
+ manager_.RemoveTextureInfo(&feature_info_, kClient3Id);
+ EXPECT_TRUE(manager_.HaveUnsafeTextures());
+ EXPECT_TRUE(manager_.HaveUnclearedMips());
+ manager_.RemoveTextureInfo(&feature_info_, kClient2Id);
+ EXPECT_FALSE(manager_.HaveUnsafeTextures());
+ EXPECT_FALSE(manager_.HaveUnclearedMips());
+}
+
+TEST_F(TextureInfoTest, ClearTexture) {
+ scoped_ptr<MockGLES2Decoder> decoder(new gles2::MockGLES2Decoder());
+ EXPECT_CALL(*decoder, ClearLevel(_, _, _, _, _, _, _, _))
+ .WillRepeatedly(Return(true));
+ manager_.SetInfoTarget(&feature_info_, info_, GL_TEXTURE_2D);
+ manager_.SetLevelInfo(&feature_info_, info_,
+ GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, false);
+ manager_.SetLevelInfo(&feature_info_, info_,
+ GL_TEXTURE_2D, 1, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, false);
+ EXPECT_FALSE(info_->SafeToRenderFrom());
+ EXPECT_TRUE(manager_.HaveUnsafeTextures());
+ EXPECT_TRUE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(2, info_->num_uncleared_mips());
+ manager_.ClearRenderableLevels(decoder.get(), info_);
+ EXPECT_TRUE(info_->SafeToRenderFrom());
+ EXPECT_FALSE(manager_.HaveUnsafeTextures());
+ EXPECT_FALSE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(0, info_->num_uncleared_mips());
+ manager_.SetLevelInfo(&feature_info_, info_,
+ GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, false);
+ manager_.SetLevelInfo(&feature_info_, info_,
+ GL_TEXTURE_2D, 1, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, false);
+ EXPECT_FALSE(info_->SafeToRenderFrom());
+ EXPECT_TRUE(manager_.HaveUnsafeTextures());
+ EXPECT_TRUE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(2, info_->num_uncleared_mips());
+ manager_.ClearTextureLevel(decoder.get(), info_, GL_TEXTURE_2D, 0);
+ EXPECT_FALSE(info_->SafeToRenderFrom());
+ EXPECT_TRUE(manager_.HaveUnsafeTextures());
+ EXPECT_TRUE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(1, info_->num_uncleared_mips());
+ manager_.ClearTextureLevel(decoder.get(), info_, GL_TEXTURE_2D, 1);
+ EXPECT_TRUE(info_->SafeToRenderFrom());
+ EXPECT_FALSE(manager_.HaveUnsafeTextures());
+ EXPECT_FALSE(manager_.HaveUnclearedMips());
+ EXPECT_EQ(0, info_->num_uncleared_mips());
+}
+
} // namespace gles2
} // namespace gpu