| Index: gpu/command_buffer/service/gles2_cmd_decoder.cc
|
| diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
|
| index c525908a1f14913df300d49dfcacb0073f1bd710..2c22ae0dfb98ec1ee6700452d3d116141a7b7e3e 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
|
| @@ -1088,9 +1112,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
|
| @@ -1183,6 +1204,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.
|
| @@ -1666,12 +1701,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_);
|
| @@ -2224,9 +2253,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(
|
| @@ -2275,19 +2305,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());
|
| }
|
| @@ -2300,8 +2370,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 {
|
| @@ -2310,8 +2382,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 {
|
| @@ -2342,7 +2416,8 @@ void GLES2DecoderImpl::UpdateParentTextureInfo() {
|
| 1, // depth
|
| 0, // border
|
| GL_RGBA,
|
| - GL_UNSIGNED_BYTE);
|
| + GL_UNSIGNED_BYTE,
|
| + true);
|
| parent_texture_manager->SetParameter(
|
| feature_info_,
|
| info,
|
| @@ -2803,8 +2878,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;
|
| @@ -2813,8 +2890,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 ||
|
| @@ -3217,10 +3296,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;
|
| @@ -3230,10 +3311,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;
|
| @@ -3243,10 +3326,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;
|
| @@ -3564,7 +3649,7 @@ error::Error GLES2DecoderImpl::HandleRegisterSharedIdsCHROMIUM(
|
| }
|
|
|
| void GLES2DecoderImpl::DoClear(GLbitfield mask) {
|
| - if (CheckFramebufferComplete("glClear")) {
|
| + if (CheckBoundFramebuffersValid("glClear")) {
|
| ApplyDirtyState();
|
| glClear(mask);
|
| }
|
| @@ -3597,12 +3682,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;
|
| @@ -3693,20 +3772,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;
|
| }
|
| @@ -3728,12 +3811,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);
|
| }
|
| }
|
|
|
| @@ -3748,11 +3835,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);
|
| }
|
|
|
| @@ -3777,15 +3868,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;
|
| @@ -3825,20 +3920,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);
|
| @@ -3872,6 +3969,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");
|
| @@ -3911,13 +4016,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;
|
| @@ -3950,7 +4058,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);
|
| }
|
| }
|
|
|
| @@ -4370,6 +4479,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
|
| @@ -4604,7 +4745,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
|
| @@ -4620,6 +4761,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;
|
| @@ -4677,7 +4822,7 @@ error::Error GLES2DecoderImpl::HandleDrawElements(
|
| return error::kNoError;
|
| }
|
|
|
| - if (!CheckFramebufferComplete("glDrawElements")) {
|
| + if (!CheckBoundFramebuffersValid("glDrawElements")) {
|
| return error::kNoError;
|
| }
|
|
|
| @@ -4694,6 +4839,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;
|
| @@ -5376,6 +5525,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.
|
| @@ -5791,6 +5944,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,
|
| @@ -5838,7 +6016,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;
|
| }
|
| @@ -6014,13 +6193,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;
|
| }
|
| @@ -6037,8 +6209,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;
|
| @@ -6138,6 +6312,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);
|
| }
|
| @@ -6159,7 +6337,6 @@ static void Clip(
|
| *out_range = range;
|
| }
|
|
|
| -
|
| void GLES2DecoderImpl::DoCopyTexImage2D(
|
| GLenum target,
|
| GLint level,
|
| @@ -6213,17 +6390,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;
|
| @@ -6241,7 +6413,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);
|
| }
|
| }
|
|
|
| @@ -6289,11 +6461,17 @@ void GLES2DecoderImpl::DoCopyTexSubImage2D(
|
| GLint copyHeight = 0;
|
| Clip(x, width, size.width(), ©X, ©Width);
|
| Clip(y, height, size.height(), ©Y, ©Height);
|
| +
|
| + 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)) {
|
| @@ -6306,6 +6484,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;
|
| @@ -6370,9 +6549,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);
|
| }
|
|
|