Commit 0d6bfdcd authored by gman@chromium.org's avatar gman@chromium.org

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
parent 13143419
...@@ -13,34 +13,36 @@ class RenderbufferAttachment ...@@ -13,34 +13,36 @@ class RenderbufferAttachment
: public FramebufferManager::FramebufferInfo::Attachment { : public FramebufferManager::FramebufferInfo::Attachment {
public: public:
explicit RenderbufferAttachment( explicit RenderbufferAttachment(
RenderbufferManager::RenderbufferInfo* render_buffer) RenderbufferManager::RenderbufferInfo* renderbuffer)
: render_buffer_(render_buffer) { : renderbuffer_(renderbuffer) {
} }
virtual ~RenderbufferAttachment() { } virtual ~RenderbufferAttachment() { }
virtual GLsizei width() const { virtual GLsizei width() const {
return render_buffer_->width(); return renderbuffer_->width();
} }
virtual GLsizei height() const { virtual GLsizei height() const {
return render_buffer_->height(); return renderbuffer_->height();
} }
virtual GLenum internal_format() const { virtual GLenum internal_format() const {
return render_buffer_->internal_format(); return renderbuffer_->internal_format();
} }
virtual GLsizei samples() const { virtual GLsizei samples() const {
return render_buffer_->samples(); return renderbuffer_->samples();
} }
virtual bool cleared() const { virtual bool cleared() const {
return render_buffer_->cleared(); return renderbuffer_->cleared();
} }
virtual void set_cleared() { virtual void SetCleared(
render_buffer_->set_cleared(); RenderbufferManager* renderbuffer_manager,
TextureManager* /* texture_manager */) {
renderbuffer_manager->SetCleared(renderbuffer_);
} }
virtual bool IsTexture(TextureManager::TextureInfo* /* texture */) const { virtual bool IsTexture(TextureManager::TextureInfo* /* texture */) const {
...@@ -51,12 +53,21 @@ class RenderbufferAttachment ...@@ -51,12 +53,21 @@ class RenderbufferAttachment
return true; return true;
} }
RenderbufferManager::RenderbufferInfo* render_buffer() const { virtual void DetachFromFramebuffer() {
return render_buffer_.get(); // 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: private:
RenderbufferManager::RenderbufferInfo::Ref render_buffer_; RenderbufferManager::RenderbufferInfo::Ref renderbuffer_;
DISALLOW_COPY_AND_ASSIGN(RenderbufferAttachment); DISALLOW_COPY_AND_ASSIGN(RenderbufferAttachment);
}; };
...@@ -99,12 +110,13 @@ class TextureAttachment ...@@ -99,12 +110,13 @@ class TextureAttachment
} }
virtual bool cleared() const { virtual bool cleared() const {
// Textures are cleared on creation. return texture_->IsLevelCleared(target_, level_);
return true;
} }
virtual void set_cleared() { virtual void SetCleared(
NOTREACHED(); RenderbufferManager* /* renderbuffer_manager */,
TextureManager* texture_manager) {
texture_manager->SetLevelCleared(texture_, target_, level_);
} }
virtual bool IsTexture(TextureManager::TextureInfo* texture) const { virtual bool IsTexture(TextureManager::TextureInfo* texture) const {
...@@ -119,6 +131,15 @@ class TextureAttachment ...@@ -119,6 +131,15 @@ class TextureAttachment
return texture_->CanRenderTo(); return texture_->CanRenderTo();
} }
virtual void DetachFromFramebuffer() {
texture_->DetachFromFramebuffer();
}
virtual bool ValidForAttachmentType(GLenum attachment_type) {
// TODO(gman): Fill this out.
return true;
}
private: private:
TextureManager::TextureInfo::Ref texture_; TextureManager::TextureInfo::Ref texture_;
GLenum target_; GLenum target_;
...@@ -133,15 +154,24 @@ FramebufferManager::~FramebufferManager() { ...@@ -133,15 +154,24 @@ FramebufferManager::~FramebufferManager() {
DCHECK(framebuffer_infos_.empty()); 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) { void FramebufferManager::Destroy(bool have_context) {
while (!framebuffer_infos_.empty()) { while (!framebuffer_infos_.empty()) {
if (have_context) { FramebufferInfo* info = framebuffer_infos_.begin()->second;
FramebufferInfo* info = framebuffer_infos_.begin()->second; if (!info->IsDeleted()) {
if (!info->IsDeleted()) { if (have_context) {
GLuint service_id = info->service_id(); GLuint service_id = info->service_id();
glDeleteFramebuffersEXT(1, &service_id); glDeleteFramebuffersEXT(1, &service_id);
info->MarkAsDeleted();
} }
info->MarkAsDeleted();
} }
framebuffer_infos_.erase(framebuffer_infos_.begin()); framebuffer_infos_.erase(framebuffer_infos_.begin());
} }
...@@ -158,8 +188,8 @@ void FramebufferManager::CreateFramebufferInfo( ...@@ -158,8 +188,8 @@ void FramebufferManager::CreateFramebufferInfo(
} }
FramebufferManager::FramebufferInfo::FramebufferInfo(GLuint service_id) FramebufferManager::FramebufferInfo::FramebufferInfo(GLuint service_id)
: service_id_(service_id) : service_id_(service_id),
, has_been_bound_(false) { has_been_bound_(false) {
} }
FramebufferManager::FramebufferInfo::~FramebufferInfo() {} FramebufferManager::FramebufferInfo::~FramebufferInfo() {}
...@@ -175,12 +205,14 @@ bool FramebufferManager::FramebufferInfo::HasUnclearedAttachment( ...@@ -175,12 +205,14 @@ bool FramebufferManager::FramebufferInfo::HasUnclearedAttachment(
return false; return false;
} }
void FramebufferManager::FramebufferInfo::MarkAttachedRenderbuffersAsCleared() { void FramebufferManager::FramebufferInfo::MarkAttachmentsAsCleared(
RenderbufferManager* renderbuffer_manager,
TextureManager* texture_manager) {
for (AttachmentMap::iterator it = attachments_.begin(); for (AttachmentMap::iterator it = attachments_.begin();
it != attachments_.end(); ++it) { it != attachments_.end(); ++it) {
Attachment* attachment = it->second; Attachment* attachment = it->second;
if (!attachment->cleared()) { if (!attachment->cleared()) {
attachment->set_cleared(); attachment->SetCleared(renderbuffer_manager, texture_manager);
} }
} }
} }
...@@ -204,18 +236,52 @@ GLenum FramebufferManager::FramebufferInfo::GetColorAttachmentFormat() const { ...@@ -204,18 +236,52 @@ GLenum FramebufferManager::FramebufferInfo::GetColorAttachmentFormat() const {
return attachment->internal_format(); 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(); for (AttachmentMap::const_iterator it = attachments_.begin();
it != attachments_.end(); ++it) { it != attachments_.end(); ++it) {
GLenum attachment_type = it->first;
Attachment* attachment = it->second; Attachment* attachment = it->second;
if (attachment->width() == 0 || attachment->height() == 0) { if (!attachment->ValidForAttachmentType(attachment_type)) {
return true; 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()) { 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( FramebufferManager::FramebufferInfo* FramebufferManager::GetFramebufferInfo(
......
...@@ -35,9 +35,13 @@ class FramebufferManager { ...@@ -35,9 +35,13 @@ class FramebufferManager {
virtual GLenum internal_format() const = 0; virtual GLenum internal_format() const = 0;
virtual GLsizei samples() const = 0; virtual GLsizei samples() const = 0;
virtual bool cleared() 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 IsTexture(TextureManager::TextureInfo* texture) const = 0;
virtual bool CanRenderTo() const = 0; virtual bool CanRenderTo() const = 0;
virtual void DetachFromFramebuffer() = 0;
virtual bool ValidForAttachmentType(GLenum attachment_type) = 0;
}; };
explicit FramebufferInfo(GLuint service_id); explicit FramebufferInfo(GLuint service_id);
...@@ -58,7 +62,9 @@ class FramebufferManager { ...@@ -58,7 +62,9 @@ class FramebufferManager {
GLenum attachment, TextureManager::TextureInfo* texture, GLenum target, GLenum attachment, TextureManager::TextureInfo* texture, GLenum target,
GLint level); GLint level);
void MarkAttachedRenderbuffersAsCleared(); void MarkAttachmentsAsCleared(
RenderbufferManager* renderbuffer_manager,
TextureManager* texture_manager);
const Attachment* GetAttachment(GLenum attachment) const; const Attachment* GetAttachment(GLenum attachment) const;
...@@ -78,11 +84,17 @@ class FramebufferManager { ...@@ -78,11 +84,17 @@ class FramebufferManager {
bool HasStencilAttachment() const; bool HasStencilAttachment() const;
GLenum GetColorAttachmentFormat() const; GLenum GetColorAttachmentFormat() const;
// We can't know if the frame buffer is complete since that is // Verify all the rules in OpenGL ES 2.0.25 4.4.5 are followed.
// implementation dependent and we'd have to check after every glTexImage // Returns GL_FRAMEBUFFER_COMPLETE if there are no reasons we know we can't
// call but we can know in certain cases that it's NOT complete which we // use this combination of attachments. Otherwise returns the value
// need to enforce the OpenGL ES 2.0 spec on top of DesktopGL. // that glCheckFramebufferStatus should return for this set of attachments.
bool IsNotComplete() const; // 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: private:
friend class FramebufferManager; friend class FramebufferManager;
...@@ -90,10 +102,7 @@ class FramebufferManager { ...@@ -90,10 +102,7 @@ class FramebufferManager {
~FramebufferInfo(); ~FramebufferInfo();
void MarkAsDeleted() { void MarkAsDeleted();
service_id_ = 0;
attachments_.clear();
}
// Service side framebuffer id. // Service side framebuffer id.
GLuint service_id_; GLuint service_id_;
......
...@@ -122,6 +122,18 @@ class GLES2Decoder : public CommonDecoder { ...@@ -122,6 +122,18 @@ class GLES2Decoder : public CommonDecoder {
// Provides detail about a lost context if one occurred. // Provides detail about a lost context if one occurred.
virtual error::ContextLostReason GetContextLostReason() = 0; 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: protected:
GLES2Decoder(); GLES2Decoder();
......
...@@ -56,6 +56,15 @@ class MockGLES2Decoder : public GLES2Decoder { ...@@ -56,6 +56,15 @@ class MockGLES2Decoder : public GLES2Decoder {
uint32* service_texture_id)); uint32* service_texture_id));
MOCK_METHOD0(GetContextLostReason, error::ContextLostReason()); MOCK_METHOD0(GetContextLostReason, error::ContextLostReason());
MOCK_CONST_METHOD1(GetCommandName, const char*(unsigned int command_id)); 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); DISALLOW_COPY_AND_ASSIGN(MockGLES2Decoder);
}; };
......
...@@ -54,8 +54,16 @@ void GLES2DecoderTestBase::SpecializedSetup<GenerateMipmap, 0>( ...@@ -54,8 +54,16 @@ void GLES2DecoderTestBase::SpecializedSetup<GenerateMipmap, 0>(
template <> template <>
void GLES2DecoderTestBase::SpecializedSetup<CheckFramebufferStatus, 0>( void GLES2DecoderTestBase::SpecializedSetup<CheckFramebufferStatus, 0>(
bool /* valid */) { bool /* valid */) {
// Give it a valid framebuffer.
DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
kServiceRenderbufferId);
DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
kServiceFramebufferId); 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 <> template <>
...@@ -91,7 +99,7 @@ void GLES2DecoderTestBase::SpecializedSetup<CopyTexSubImage2D, 0>(bool valid) { ...@@ -91,7 +99,7 @@ void GLES2DecoderTestBase::SpecializedSetup<CopyTexSubImage2D, 0>(bool valid) {
DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
DoTexImage2D( DoTexImage2D(
GL_TEXTURE_2D, 2, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, 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>( ...@@ -116,13 +124,6 @@ void GLES2DecoderTestBase::SpecializedSetup<FramebufferRenderbuffer, 0>(
if (valid) { if (valid) {
EXPECT_CALL(*gl_, GetError()) EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR)) .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)) .WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation(); .RetiresOnSaturation();
} }
...@@ -136,13 +137,6 @@ void GLES2DecoderTestBase::SpecializedSetup<FramebufferTexture2D, 0>( ...@@ -136,13 +137,6 @@ void GLES2DecoderTestBase::SpecializedSetup<FramebufferTexture2D, 0>(
if (valid) { if (valid) {
EXPECT_CALL(*gl_, GetError()) EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR)) .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)) .WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation(); .RetiresOnSaturation();
} }
......
...@@ -66,6 +66,52 @@ class GLES2DecoderTestBase : public testing::Test { ...@@ -66,6 +66,52 @@ class GLES2DecoderTestBase : public testing::Test {
static const int kBackBufferWidth = 128; static const int kBackBufferWidth = 128;
static const int kBackBufferHeight = 64; 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 to call glGenXXX functions.
template <typename T> template <typename T>
void GenHelper(GLuint client_id) { void GenHelper(GLuint client_id) {
...@@ -197,6 +243,9 @@ class GLES2DecoderTestBase : public testing::Test { ...@@ -197,6 +243,9 @@ class GLES2DecoderTestBase : public testing::Test {
// Setups up a shader for testing glUniform. // Setups up a shader for testing glUniform.
void SetupShaderForUniform(); void SetupShaderForUniform();
void SetupDefaultProgram();
void SetupCubemapProgram();
void SetupTexture();
// Note that the error is returned as GLint instead of GLenum. // Note that the error is returned as GLint instead of GLenum.
// This is because there is a mismatch in the types of GLenum and // This is because there is a mismatch in the types of GLenum and
...@@ -228,14 +277,56 @@ class GLES2DecoderTestBase : public testing::Test { ...@@ -228,14 +277,56 @@ class GLES2DecoderTestBase : public testing::Test {
void DoDeleteShader(GLuint client_id, GLuint service_id); void DoDeleteShader(GLuint client_id, GLuint service_id);
void DoDeleteTexture(GLuint client_id, GLuint service_id); void DoDeleteTexture(GLuint client_id, GLuint service_id);
void DoTexImage2D(GLenum target, GLint level, GLenum internal_format, void DoTexImage2D(
GLsizei width, GLsizei height, GLint border, GLenum target, GLint level, GLenum internal_format,
GLenum format, GLenum type, GLsizei width, GLsizei height, GLint border,
uint32 shared_memory_id, uint32 shared_memory_offset); 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( void DoVertexAttribPointer(
GLuint index, GLint size, GLenum type, GLsizei stride, GLuint offset); 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, GLuint clear_bits,
GLclampf restore_red, GLclampf restore_red,
GLclampf restore_green, GLclampf restore_green,
...@@ -258,6 +349,12 @@ class GLES2DecoderTestBase : public testing::Test { ...@@ -258,6 +349,12 @@ class GLES2DecoderTestBase : public testing::Test {
void SetupExpectationsForApplyingDefaultDirtyState(); void SetupExpectationsForApplyingDefaultDirtyState();
void AddExpectationsForSimulatedAttrib0WithError(
GLsizei num_vertices, GLuint buffer_id, GLenum error);
void AddExpectationsForSimulatedAttrib0(
GLsizei num_vertices, GLuint buffer_id);
GLvoid* BufferOffset(unsigned i) { GLvoid* BufferOffset(unsigned i) {
return static_cast<int8 *>(NULL)+(i); return static_cast<int8 *>(NULL)+(i);
} }
...@@ -286,6 +383,8 @@ class GLES2DecoderTestBase : public testing::Test { ...@@ -286,6 +383,8 @@ class GLES2DecoderTestBase : public testing::Test {
GLuint client_shader_id_; GLuint client_shader_id_;
GLuint client_texture_id_; GLuint client_texture_id_;
GLuint client_element_buffer_id_; GLuint client_element_buffer_id_;
GLuint client_vertex_shader_id_;
GLuint client_fragment_shader_id_;
uint32 shared_memory_id_; uint32 shared_memory_id_;
uint32 shared_memory_offset_; uint32 shared_memory_offset_;
...@@ -344,80 +443,13 @@ class GLES2DecoderTestBase : public testing::Test { ...@@ -344,80 +443,13 @@ class GLES2DecoderTestBase : public testing::Test {
class GLES2DecoderWithShaderTestBase : public GLES2DecoderTestBase { class GLES2DecoderWithShaderTestBase : public GLES2DecoderTestBase {
public: public:
GLES2DecoderWithShaderTestBase() GLES2DecoderWithShaderTestBase()
: GLES2DecoderTestBase(), : GLES2DecoderTestBase() {
client_vertex_shader_id_(121),
client_fragment_shader_id_(122) {
} }
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: protected:
virtual void SetUp(); virtual void SetUp();
virtual void TearDown(); 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 } // namespace gles2
......
...@@ -13,7 +13,8 @@ namespace gles2 { ...@@ -13,7 +13,8 @@ namespace gles2 {
RenderbufferManager::RenderbufferManager( RenderbufferManager::RenderbufferManager(
GLint max_renderbuffer_size, GLint max_samples) GLint max_renderbuffer_size, GLint max_samples)
: max_renderbuffer_size_(max_renderbuffer_size), : max_renderbuffer_size_(max_renderbuffer_size),
max_samples_(max_samples) { max_samples_(max_samples),
num_uncleared_renderbuffers_(0) {
} }
RenderbufferManager::~RenderbufferManager() { RenderbufferManager::~RenderbufferManager() {
...@@ -34,14 +35,39 @@ void RenderbufferManager::Destroy(bool have_context) { ...@@ -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( void RenderbufferManager::CreateRenderbufferInfo(
GLuint client_id, GLuint service_id) { GLuint client_id, GLuint service_id) {
RenderbufferInfo::Ref info(new RenderbufferInfo(service_id));
std::pair<RenderbufferInfoMap::iterator, bool> result = std::pair<RenderbufferInfoMap::iterator, bool> result =
renderbuffer_infos_.insert( renderbuffer_infos_.insert(std::make_pair(client_id, info));
std::make_pair(
client_id,
RenderbufferInfo::Ref(new RenderbufferInfo(service_id))));
DCHECK(result.second); DCHECK(result.second);
if (!info->cleared()) {
++num_uncleared_renderbuffers_;
}
} }
RenderbufferManager::RenderbufferInfo* RenderbufferManager::GetRenderbufferInfo( RenderbufferManager::RenderbufferInfo* RenderbufferManager::GetRenderbufferInfo(
...@@ -53,7 +79,11 @@ RenderbufferManager::RenderbufferInfo* RenderbufferManager::GetRenderbufferInfo( ...@@ -53,7 +79,11 @@ RenderbufferManager::RenderbufferInfo* RenderbufferManager::GetRenderbufferInfo(
void RenderbufferManager::RemoveRenderbufferInfo(GLuint client_id) { void RenderbufferManager::RemoveRenderbufferInfo(GLuint client_id) {
RenderbufferInfoMap::iterator it = renderbuffer_infos_.find(client_id); RenderbufferInfoMap::iterator it = renderbuffer_infos_.find(client_id);
if (it != renderbuffer_infos_.end()) { if (it != renderbuffer_infos_.end()) {
it->second->MarkAsDeleted(); RenderbufferInfo* info = it->second;
if (!info->cleared()) {
--num_uncleared_renderbuffers_;
}
info->MarkAsDeleted();
renderbuffer_infos_.erase(it); renderbuffer_infos_.erase(it);
} }
} }
......
...@@ -25,7 +25,7 @@ class RenderbufferManager { ...@@ -25,7 +25,7 @@ class RenderbufferManager {
explicit RenderbufferInfo(GLuint service_id) explicit RenderbufferInfo(GLuint service_id)
: service_id_(service_id), : service_id_(service_id),
cleared_(false), cleared_(true),
has_been_bound_(false), has_been_bound_(false),
samples_(0), samples_(0),
internal_format_(GL_RGBA4), internal_format_(GL_RGBA4),
...@@ -41,10 +41,6 @@ class RenderbufferManager { ...@@ -41,10 +41,6 @@ class RenderbufferManager {
return cleared_; return cleared_;
} }
void set_cleared() {
cleared_ = true;
}
GLenum internal_format() const { GLenum internal_format() const {
return internal_format_; return internal_format_;
} }
...@@ -61,15 +57,6 @@ class RenderbufferManager { ...@@ -61,15 +57,6 @@ class RenderbufferManager {
return height_; 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 { bool IsDeleted() const {
return service_id_ == 0; return service_id_ == 0;
} }
...@@ -88,6 +75,19 @@ class RenderbufferManager { ...@@ -88,6 +75,19 @@ class RenderbufferManager {
~RenderbufferInfo() { } ~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() { void MarkAsDeleted() {
service_id_ = 0; service_id_ = 0;
} }
...@@ -123,6 +123,16 @@ class RenderbufferManager { ...@@ -123,6 +123,16 @@ class RenderbufferManager {
return max_samples_; 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. // Must call before destruction.
void Destroy(bool have_context); void Destroy(bool have_context);
...@@ -142,6 +152,8 @@ class RenderbufferManager { ...@@ -142,6 +152,8 @@ class RenderbufferManager {
GLint max_renderbuffer_size_; GLint max_renderbuffer_size_;
GLint max_samples_; GLint max_samples_;
int num_uncleared_renderbuffers_;
// Info for each renderbuffer in the system. // Info for each renderbuffer in the system.
typedef base::hash_map<GLuint, RenderbufferInfo::Ref> RenderbufferInfoMap; typedef base::hash_map<GLuint, RenderbufferInfo::Ref> RenderbufferInfoMap;
RenderbufferInfoMap renderbuffer_infos_; RenderbufferInfoMap renderbuffer_infos_;
......
...@@ -50,12 +50,14 @@ TEST_F(RenderbufferManagerTest, Basic) { ...@@ -50,12 +50,14 @@ TEST_F(RenderbufferManagerTest, Basic) {
const GLuint kClient2Id = 2; const GLuint kClient2Id = 2;
EXPECT_EQ(kMaxSize, manager_.max_renderbuffer_size()); EXPECT_EQ(kMaxSize, manager_.max_renderbuffer_size());
EXPECT_EQ(kMaxSamples, manager_.max_samples()); EXPECT_EQ(kMaxSamples, manager_.max_samples());
EXPECT_FALSE(manager_.HaveUnclearedRenderbuffers());
// Check we can create renderbuffer. // Check we can create renderbuffer.
manager_.CreateRenderbufferInfo(kClient1Id, kService1Id); manager_.CreateRenderbufferInfo(kClient1Id, kService1Id);
// Check renderbuffer got created. // Check renderbuffer got created.
RenderbufferManager::RenderbufferInfo* info1 = RenderbufferManager::RenderbufferInfo* info1 =
manager_.GetRenderbufferInfo(kClient1Id); manager_.GetRenderbufferInfo(kClient1Id);
ASSERT_TRUE(info1 != NULL); ASSERT_TRUE(info1 != NULL);
EXPECT_FALSE(manager_.HaveUnclearedRenderbuffers());
GLuint client_id = 0; GLuint client_id = 0;
EXPECT_TRUE(manager_.GetClientId(info1->service_id(), &client_id)); EXPECT_TRUE(manager_.GetClientId(info1->service_id(), &client_id));
EXPECT_EQ(kClient1Id, client_id); EXPECT_EQ(kClient1Id, client_id);
...@@ -66,6 +68,7 @@ TEST_F(RenderbufferManagerTest, Basic) { ...@@ -66,6 +68,7 @@ TEST_F(RenderbufferManagerTest, Basic) {
// Check we can't get the renderbuffer after we remove it. // Check we can't get the renderbuffer after we remove it.
manager_.RemoveRenderbufferInfo(kClient1Id); manager_.RemoveRenderbufferInfo(kClient1Id);
EXPECT_TRUE(manager_.GetRenderbufferInfo(kClient1Id) == NULL); EXPECT_TRUE(manager_.GetRenderbufferInfo(kClient1Id) == NULL);
EXPECT_FALSE(manager_.HaveUnclearedRenderbuffers());
} }
TEST_F(RenderbufferManagerTest, Destroy) { TEST_F(RenderbufferManagerTest, Destroy) {
...@@ -99,9 +102,6 @@ TEST_F(RenderbufferManagerTest, RenderbufferInfo) { ...@@ -99,9 +102,6 @@ TEST_F(RenderbufferManagerTest, RenderbufferInfo) {
EXPECT_EQ(static_cast<GLenum>(GL_RGBA4), info1->internal_format()); EXPECT_EQ(static_cast<GLenum>(GL_RGBA4), info1->internal_format());
EXPECT_EQ(0, info1->width()); EXPECT_EQ(0, info1->width());
EXPECT_EQ(0, info1->height()); EXPECT_EQ(0, info1->height());
EXPECT_FALSE(info1->cleared());
info1->set_cleared();
EXPECT_TRUE(info1->cleared()); EXPECT_TRUE(info1->cleared());
// Check if we set the info it gets marked as not cleared. // Check if we set the info it gets marked as not cleared.
...@@ -109,13 +109,24 @@ TEST_F(RenderbufferManagerTest, RenderbufferInfo) { ...@@ -109,13 +109,24 @@ TEST_F(RenderbufferManagerTest, RenderbufferInfo) {
const GLenum kFormat = GL_RGBA; const GLenum kFormat = GL_RGBA;
const GLsizei kWidth = 128; const GLsizei kWidth = 128;
const GLsizei kHeight = 64; const GLsizei kHeight = 64;
info1->SetInfo(kSamples, kFormat, kWidth, kHeight); manager_.SetInfo(info1, kSamples, kFormat, kWidth, kHeight);
EXPECT_EQ(kSamples, info1->samples()); EXPECT_EQ(kSamples, info1->samples());
EXPECT_EQ(kFormat, info1->internal_format()); EXPECT_EQ(kFormat, info1->internal_format());
EXPECT_EQ(kWidth, info1->width()); EXPECT_EQ(kWidth, info1->width());
EXPECT_EQ(kHeight, info1->height()); EXPECT_EQ(kHeight, info1->height());
EXPECT_FALSE(info1->cleared()); EXPECT_FALSE(info1->cleared());
EXPECT_FALSE(info1->IsDeleted()); 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 } // namespace gles2
......
...@@ -16,6 +16,7 @@ namespace gpu { ...@@ -16,6 +16,7 @@ namespace gpu {
namespace gles2 { namespace gles2 {
class FeatureInfo; class FeatureInfo;
class GLES2Decoder;
// This class keeps track of the textures and their sizes so we can do NPOT and // This class keeps track of the textures and their sizes so we can do NPOT and
// texture complete checking. // texture complete checking.
...@@ -32,6 +33,8 @@ class TextureManager { ...@@ -32,6 +33,8 @@ class TextureManager {
explicit TextureInfo(GLuint service_id) explicit TextureInfo(GLuint service_id)
: service_id_(service_id), : service_id_(service_id),
deleted_(false), deleted_(false),
cleared_(true),
num_uncleared_mips_(0),
target_(0), target_(0),
min_filter_(GL_NEAREST_MIPMAP_LINEAR), min_filter_(GL_NEAREST_MIPMAP_LINEAR),
mag_filter_(GL_LINEAR), mag_filter_(GL_LINEAR),
...@@ -63,6 +66,10 @@ class TextureManager { ...@@ -63,6 +66,10 @@ class TextureManager {
return wrap_t_; return wrap_t_;
} }
int num_uncleared_mips() const {
return num_uncleared_mips_;
}
// True if this texture meets all the GLES2 criteria for rendering. // True if this texture meets all the GLES2 criteria for rendering.
// See section 3.8.2 of the GLES2 spec. // See section 3.8.2 of the GLES2 spec.
bool CanRender(const FeatureInfo* feature_info) const; bool CanRender(const FeatureInfo* feature_info) const;
...@@ -101,6 +108,10 @@ class TextureManager { ...@@ -101,6 +108,10 @@ class TextureManager {
return npot_; return npot_;
} }
bool SafeToRenderFrom() const {
return cleared_;
}
// Returns true if mipmaps can be generated by GL. // Returns true if mipmaps can be generated by GL.
bool CanGenerateMipmaps(const FeatureInfo* feature_info) const; bool CanGenerateMipmaps(const FeatureInfo* feature_info) const;
...@@ -146,7 +157,7 @@ class TextureManager { ...@@ -146,7 +157,7 @@ class TextureManager {
} }
void DetachFromFramebuffer() { void DetachFromFramebuffer() {
DCHECK(framebuffer_attachment_count_ > 0); DCHECK_GT(framebuffer_attachment_count_, 0);
--framebuffer_attachment_count_; --framebuffer_attachment_count_;
} }
...@@ -158,6 +169,9 @@ class TextureManager { ...@@ -158,6 +169,9 @@ class TextureManager {
return stream_texture_; return stream_texture_;
} }
// Whether a particular level/face is cleared.
bool IsLevelCleared(GLenum target, GLint level);
private: private:
friend class TextureManager; friend class TextureManager;
friend class base::RefCounted<TextureInfo>; friend class base::RefCounted<TextureInfo>;
...@@ -166,7 +180,9 @@ class TextureManager { ...@@ -166,7 +180,9 @@ class TextureManager {
struct LevelInfo { struct LevelInfo {
LevelInfo() LevelInfo()
: valid(false), : cleared(true),
target(0),
level(-1),
internal_format(0), internal_format(0),
width(0), width(0),
height(0), height(0),
...@@ -176,7 +192,9 @@ class TextureManager { ...@@ -176,7 +192,9 @@ class TextureManager {
type(0) { type(0) {
} }
bool valid; bool cleared;
GLenum target;
GLint level;
GLenum internal_format; GLenum internal_format;
GLsizei width; GLsizei width;
GLsizei height; GLsizei height;
...@@ -197,7 +215,22 @@ class TextureManager { ...@@ -197,7 +215,22 @@ class TextureManager {
GLsizei depth, GLsizei depth,
GLint border, GLint border,
GLenum format, 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. // Sets a texture parameter.
// TODO(gman): Expand to SetParameteri,f,iv,fv // TODO(gman): Expand to SetParameteri,f,iv,fv
...@@ -236,6 +269,11 @@ class TextureManager { ...@@ -236,6 +269,11 @@ class TextureManager {
// Whether this texture has been deleted. // Whether this texture has been deleted.
bool 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. // The target. 0 if unset, otherwise GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP.
GLenum target_; GLenum target_;
...@@ -333,7 +371,11 @@ class TextureManager { ...@@ -333,7 +371,11 @@ class TextureManager {
GLsizei depth, GLsizei depth,
GLint border, GLint border,
GLenum format, 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 // Sets a texture parameter of a TextureInfo
// TODO(gman): Expand to SetParameteri,f,iv,fv // TODO(gman): Expand to SetParameteri,f,iv,fv
...@@ -343,9 +385,14 @@ class TextureManager { ...@@ -343,9 +385,14 @@ class TextureManager {
// Makes each of the mip levels as though they were generated. // Makes each of the mip levels as though they were generated.
// Returns false if that's not allowed for the given texture. // Returns false if that's not allowed for the given texture.
bool MarkMipmapsGenerated( bool MarkMipmapsGenerated(const FeatureInfo* feature_info, TextureInfo* info);
const FeatureInfo* feature_info,
TextureManager::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. // Creates a new texture info.
TextureInfo* CreateTextureInfo( TextureInfo* CreateTextureInfo(
...@@ -378,6 +425,14 @@ class TextureManager { ...@@ -378,6 +425,14 @@ class TextureManager {
return num_unrenderable_textures_ > 0; 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 { GLuint black_texture_id(GLenum target) const {
switch (target) { switch (target) {
case GL_SAMPLER_2D: case GL_SAMPLER_2D:
...@@ -403,6 +458,8 @@ class TextureManager { ...@@ -403,6 +458,8 @@ class TextureManager {
GLint max_cube_map_levels_; GLint max_cube_map_levels_;
int num_unrenderable_textures_; 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. // Black (0,0,0,1) textures for when non-renderable textures are used.
// NOTE: There is no corresponding TextureInfo for these textures. // NOTE: There is no corresponding TextureInfo for these textures.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment