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
: 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(
......
......@@ -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_;
......
......@@ -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();
......
......@@ -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);
};
......
......@@ -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();
}
......
......@@ -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
......
......@@ -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);
}
}
......
......@@ -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_;
......
......@@ -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
......
......@@ -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.
......
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