diff options
author | Andras Becsi <andras.becsi@digia.com> | 2014-03-18 13:16:26 +0100 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2014-03-20 15:55:39 +0100 |
commit | 3f0f86b0caed75241fa71c95a5d73bc0164348c5 (patch) | |
tree | 92b9fb00f2e9e90b0be2262093876d4f43b6cd13 /chromium/gpu/command_buffer/service/gles2_cmd_decoder.cc | |
parent | e90d7c4b152c56919d963987e2503f9909a666d2 (diff) | |
download | qtwebengine-chromium-3f0f86b0caed75241fa71c95a5d73bc0164348c5.tar.gz |
Update to new stable branch 1750
This also includes an updated ninja and chromium dependencies
needed on Windows.
Change-Id: Icd597d80ed3fa4425933c9f1334c3c2e31291c42
Reviewed-by: Zoltan Arvai <zarvai@inf.u-szeged.hu>
Reviewed-by: Zeno Albisser <zeno.albisser@digia.com>
Diffstat (limited to 'chromium/gpu/command_buffer/service/gles2_cmd_decoder.cc')
-rw-r--r-- | chromium/gpu/command_buffer/service/gles2_cmd_decoder.cc | 1196 |
1 files changed, 701 insertions, 495 deletions
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_decoder.cc b/chromium/gpu/command_buffer/service/gles2_cmd_decoder.cc index 120359ceae8..c2fcee2933a 100644 --- a/chromium/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/chromium/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -14,15 +14,12 @@ #include <vector> #include "base/at_exit.h" -#include "base/atomicops.h" #include "base/bind.h" #include "base/command_line.h" #include "base/debug/trace_event.h" -#if defined(OS_MACOSX) -#include "base/mac/scoped_cftyperef.h" -#endif #include "base/memory/scoped_ptr.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" #include "build/build_config.h" #define GLES2_GPU_SERVICE 1 #include "gpu/command_buffer/common/debug_marker_manager.h" @@ -292,11 +289,11 @@ static void EnableDisable(GLenum pname, bool enable) { class ScopedGLErrorSuppressor { public: explicit ScopedGLErrorSuppressor( - const char* function_name, GLES2DecoderImpl* decoder); + const char* function_name, ErrorState* error_state); ~ScopedGLErrorSuppressor(); private: const char* function_name_; - GLES2DecoderImpl* decoder_; + ErrorState* error_state_; DISALLOW_COPY_AND_ASSIGN(ScopedGLErrorSuppressor); }; @@ -305,11 +302,11 @@ class ScopedGLErrorSuppressor { // unit zero in case the client has changed that to something invalid. class ScopedTexture2DBinder { public: - ScopedTexture2DBinder(GLES2DecoderImpl* decoder, GLuint id); + ScopedTexture2DBinder(ContextState* state, GLuint id); ~ScopedTexture2DBinder(); private: - GLES2DecoderImpl* decoder_; + ContextState* state_; DISALLOW_COPY_AND_ASSIGN(ScopedTexture2DBinder); }; @@ -317,11 +314,11 @@ class ScopedTexture2DBinder { // object goes out of scope. class ScopedRenderBufferBinder { public: - ScopedRenderBufferBinder(GLES2DecoderImpl* decoder, GLuint id); + ScopedRenderBufferBinder(ContextState* state, GLuint id); ~ScopedRenderBufferBinder(); private: - GLES2DecoderImpl* decoder_; + ContextState* state_; DISALLOW_COPY_AND_ASSIGN(ScopedRenderBufferBinder); }; @@ -357,7 +354,7 @@ class ScopedResolvedFrameBufferBinder { // Encapsulates an OpenGL texture. class BackTexture { public: - explicit BackTexture(GLES2DecoderImpl* decoder); + explicit BackTexture(MemoryTracker* memory_tracker, ContextState* state); ~BackTexture(); // Create a new render texture. @@ -390,8 +387,8 @@ class BackTexture { } private: - GLES2DecoderImpl* decoder_; MemoryTypeTracker memory_tracker_; + ContextState* state_; size_t bytes_allocated_; GLuint id_; gfx::Size size_; @@ -401,14 +398,20 @@ class BackTexture { // Encapsulates an OpenGL render buffer of any format. class BackRenderbuffer { public: - explicit BackRenderbuffer(GLES2DecoderImpl* decoder); + explicit BackRenderbuffer( + RenderbufferManager* renderbuffer_manager, + MemoryTracker* memory_tracker, + ContextState* state); ~BackRenderbuffer(); // Create a new render buffer. void Create(); // Set the initial size and format of a render buffer or resize it. - bool AllocateStorage(const gfx::Size& size, GLenum format, GLsizei samples); + bool AllocateStorage(const FeatureInfo* feature_info, + const gfx::Size& size, + GLenum format, + GLsizei samples); // Destroy the render buffer. This must be explicitly called before destroying // this object. @@ -427,8 +430,9 @@ class BackRenderbuffer { } private: - GLES2DecoderImpl* decoder_; + RenderbufferManager* renderbuffer_manager_; MemoryTypeTracker memory_tracker_; + ContextState* state_; size_t bytes_allocated_; GLuint id_; DISALLOW_COPY_AND_ASSIGN(BackRenderbuffer); @@ -500,24 +504,10 @@ GLES2Decoder::GLES2Decoder() GLES2Decoder::~GLES2Decoder() { } -bool GLES2Decoder::testing_force_is_angle_; - -void GLES2Decoder::set_testing_force_is_angle(bool force) { - testing_force_is_angle_ = force; -} - -bool GLES2Decoder::IsAngle() { -#if defined(OS_WIN) - return testing_force_is_angle_ || - gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2; -#else - return testing_force_is_angle_; -#endif -} - // This class implements GLES2Decoder so we don't have to expose all the GLES2 // cmd stuff to outside this class. -class GLES2DecoderImpl : public GLES2Decoder { +class GLES2DecoderImpl : public GLES2Decoder, + public FramebufferManager::TextureDetachObserver { public: // Used by PrepForSetUniformByLocation to validate types. struct BaseUniformInfo { @@ -554,6 +544,7 @@ class GLES2DecoderImpl : public GLES2Decoder { virtual GLES2Util* GetGLES2Util() OVERRIDE { return &util_; } virtual gfx::GLContext* GetGLContext() OVERRIDE { return context_.get(); } virtual ContextGroup* GetContextGroup() OVERRIDE { return group_.get(); } + virtual Capabilities GetCapabilities() OVERRIDE; virtual void RestoreState() const OVERRIDE; virtual void RestoreActiveTexture() const OVERRIDE { @@ -623,8 +614,6 @@ class GLES2DecoderImpl : public GLES2Decoder { // Restores the current state to the user's settings. void RestoreCurrentFramebufferBindings(); - void RestoreCurrentRenderbufferBindings(); - void RestoreCurrentTexture2DBindings(); // Sets DEPTH_TEST, STENCIL_TEST and color mask for the current framebuffer. void ApplyDirtyState(); @@ -639,12 +628,33 @@ class GLES2DecoderImpl : public GLES2Decoder { virtual error::ContextLostReason GetContextLostReason() OVERRIDE; + // Overridden from FramebufferManager::TextureDetachObserver: + virtual void OnTextureRefDetachedFromFramebuffer( + TextureRef* texture) OVERRIDE; + + // Helpers to facilitate calling into compatible extensions. + static void RenderbufferStorageMultisampleHelper( + const FeatureInfo* feature_info, + GLenum target, + GLsizei samples, + GLenum internal_format, + GLsizei width, + GLsizei height); + + void BlitFramebufferHelper(GLint srcX0, + GLint srcY0, + GLint srcX1, + GLint srcY1, + GLint dstX0, + GLint dstY0, + GLint dstX1, + GLint dstY1, + GLbitfield mask, + GLenum filter); + private: friend class ScopedFrameBufferBinder; - friend class ScopedGLErrorSuppressor; friend class ScopedResolvedFrameBufferBinder; - friend class BackTexture; - friend class BackRenderbuffer; friend class BackFramebuffer; // Initialize or re-initialize the shader translator. @@ -753,6 +763,7 @@ class GLES2DecoderImpl : public GLES2Decoder { // Get the format of the currently bound frame buffer (either FBO or regular // back buffer) + GLenum GetBoundReadFrameBufferTextureType(); GLenum GetBoundReadFrameBufferInternalFormat(); GLenum GetBoundDrawFrameBufferInternalFormat(); @@ -901,9 +912,9 @@ class GLES2DecoderImpl : public GLES2Decoder { void LogClientServiceMapping( const char* function_name, GLuint client_id, GLuint service_id) { if (service_logging_) { - DLOG(INFO) << "[" << logger_.GetLogPrefix() << "] " << function_name - << ": client_id = " << client_id - << ", service_id = " << service_id; + VLOG(1) << "[" << logger_.GetLogPrefix() << "] " << function_name + << ": client_id = " << client_id + << ", service_id = " << service_id; } } template<typename T> @@ -1143,8 +1154,8 @@ class GLES2DecoderImpl : public GLES2Decoder { void DoBindVertexArrayOES(GLuint array); void EmulateVertexArrayState(); - // Wrapper for glBlitFramebufferEXT. - void DoBlitFramebufferEXT( + // Wrapper for glBlitFramebufferCHROMIUM. + void DoBlitFramebufferCHROMIUM( GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); @@ -1286,11 +1297,23 @@ class GLES2DecoderImpl : public GLES2Decoder { void DoRenderbufferStorage( GLenum target, GLenum internalformat, GLsizei width, GLsizei height); - // Wrapper for glRenderbufferStorageMultisampleEXT. - void DoRenderbufferStorageMultisample( + // Handler for glRenderbufferStorageMultisampleCHROMIUM. + void DoRenderbufferStorageMultisampleCHROMIUM( + GLenum target, GLsizei samples, GLenum internalformat, + GLsizei width, GLsizei height); + + // Handler for glRenderbufferStorageMultisampleEXT + // (multisampled_render_to_texture). + void DoRenderbufferStorageMultisampleEXT( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); + // Common validation for multisample extensions. + bool ValidateRenderbufferStorageMultisample(GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height); + // Verifies that the currently bound multisample renderbuffer is valid // Very slow! Only done on platforms with driver bugs that return invalid // buffers under memory pressure @@ -1376,9 +1399,14 @@ class GLES2DecoderImpl : public GLES2Decoder { // buffer and bind the texture implicitly. void UpdateStreamTextureIfNeeded(Texture* texture, GLuint texture_unit_index); - // Returns false if unrenderable textures were replaced. + // If an image is bound to texture, this will call Will/DidUseTexImage + // if needed. + void DoWillUseTexImageIfNeeded(Texture* texture, GLenum textarget); + void DoDidUseTexImageIfNeeded(Texture* texture, GLenum textarget); + + // Returns false if textures were replaced. bool PrepareTexturesForRender(); - void RestoreStateForNonRenderableTextures(); + void RestoreStateForTextures(); // Returns true if GL_FIXED attribs were simulated. bool SimulateFixedAttribs( @@ -1421,10 +1449,10 @@ class GLES2DecoderImpl : public GLES2Decoder { switch (target) { case GL_FRAMEBUFFER: case GL_DRAW_FRAMEBUFFER_EXT: - framebuffer = state_.bound_draw_framebuffer.get(); + framebuffer = framebuffer_state_.bound_draw_framebuffer.get(); break; case GL_READ_FRAMEBUFFER_EXT: - framebuffer = state_.bound_read_framebuffer.get(); + framebuffer = framebuffer_state_.bound_read_framebuffer.get(); break; default: NOTREACHED(); @@ -1501,16 +1529,36 @@ class GLES2DecoderImpl : public GLES2Decoder { bool ShouldDeferDraws() { return !offscreen_target_frame_buffer_.get() && - state_.bound_draw_framebuffer.get() == NULL && + framebuffer_state_.bound_draw_framebuffer.get() == NULL && surface_->DeferDraws(); } bool ShouldDeferReads() { return !offscreen_target_frame_buffer_.get() && - state_.bound_read_framebuffer.get() == NULL && + framebuffer_state_.bound_read_framebuffer.get() == NULL && surface_->DeferDraws(); } + error::Error WillAccessBoundFramebufferForDraw() { + if (ShouldDeferDraws()) + return error::kDeferCommandUntilLater; + if (!offscreen_target_frame_buffer_.get() && + !framebuffer_state_.bound_draw_framebuffer.get() && + !surface_->SetBackbufferAllocation(true)) + return error::kLostContext; + return error::kNoError; + } + + error::Error WillAccessBoundFramebufferForRead() { + if (ShouldDeferReads()) + return error::kDeferCommandUntilLater; + if (!offscreen_target_frame_buffer_.get() && + !framebuffer_state_.bound_read_framebuffer.get() && + !surface_->SetBackbufferAllocation(true)) + return error::kLostContext; + return error::kNoError; + } + void ProcessPendingReadPixels(); void FinishReadPixels(const cmds::ReadPixels& c, GLuint buffer); @@ -1684,22 +1732,34 @@ class GLES2DecoderImpl : public GLES2Decoder { }; ScopedGLErrorSuppressor::ScopedGLErrorSuppressor( - const char* function_name, GLES2DecoderImpl* decoder) + const char* function_name, ErrorState* error_state) : function_name_(function_name), - decoder_(decoder) { - ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(decoder_->GetErrorState(), - function_name_); + error_state_(error_state) { + ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state_, function_name_); } ScopedGLErrorSuppressor::~ScopedGLErrorSuppressor() { - ERRORSTATE_CLEAR_REAL_GL_ERRORS(decoder_->GetErrorState(), function_name_); + ERRORSTATE_CLEAR_REAL_GL_ERRORS(error_state_, function_name_); +} + +static void RestoreCurrentTexture2DBindings(ContextState* state) { + TextureUnit& info = state->texture_units[0]; + GLuint last_id; + if (info.bound_texture_2d.get()) { + last_id = info.bound_texture_2d->service_id(); + } else { + last_id = 0; + } + + glBindTexture(GL_TEXTURE_2D, last_id); + glActiveTexture(GL_TEXTURE0 + state->active_texture_unit); } -ScopedTexture2DBinder::ScopedTexture2DBinder(GLES2DecoderImpl* decoder, +ScopedTexture2DBinder::ScopedTexture2DBinder(ContextState* state, GLuint id) - : decoder_(decoder) { + : state_(state) { ScopedGLErrorSuppressor suppressor( - "ScopedTexture2DBinder::ctor", decoder_); + "ScopedTexture2DBinder::ctor", state_->GetErrorState()); // TODO(apatrick): Check if there are any other states that need to be reset // before binding a new texture. @@ -1709,51 +1769,52 @@ ScopedTexture2DBinder::ScopedTexture2DBinder(GLES2DecoderImpl* decoder, ScopedTexture2DBinder::~ScopedTexture2DBinder() { ScopedGLErrorSuppressor suppressor( - "ScopedTexture2DBinder::dtor", decoder_); - decoder_->RestoreCurrentTexture2DBindings(); + "ScopedTexture2DBinder::dtor", state_->GetErrorState()); + RestoreCurrentTexture2DBindings(state_); } -ScopedRenderBufferBinder::ScopedRenderBufferBinder(GLES2DecoderImpl* decoder, +ScopedRenderBufferBinder::ScopedRenderBufferBinder(ContextState* state, GLuint id) - : decoder_(decoder) { + : state_(state) { ScopedGLErrorSuppressor suppressor( - "ScopedRenderBufferBinder::ctor", decoder_); + "ScopedRenderBufferBinder::ctor", state_->GetErrorState()); glBindRenderbufferEXT(GL_RENDERBUFFER, id); } ScopedRenderBufferBinder::~ScopedRenderBufferBinder() { ScopedGLErrorSuppressor suppressor( - "ScopedRenderBufferBinder::dtor", decoder_); - decoder_->RestoreCurrentRenderbufferBindings(); + "ScopedRenderBufferBinder::dtor", state_->GetErrorState()); + state_->RestoreRenderbufferBindings(); } ScopedFrameBufferBinder::ScopedFrameBufferBinder(GLES2DecoderImpl* decoder, GLuint id) : decoder_(decoder) { ScopedGLErrorSuppressor suppressor( - "ScopedFrameBufferBinder::ctor", decoder_); + "ScopedFrameBufferBinder::ctor", decoder_->GetErrorState()); glBindFramebufferEXT(GL_FRAMEBUFFER, id); decoder->OnFboChanged(); } ScopedFrameBufferBinder::~ScopedFrameBufferBinder() { ScopedGLErrorSuppressor suppressor( - "ScopedFrameBufferBinder::dtor", decoder_); + "ScopedFrameBufferBinder::dtor", decoder_->GetErrorState()); decoder_->RestoreCurrentFramebufferBindings(); } ScopedResolvedFrameBufferBinder::ScopedResolvedFrameBufferBinder( GLES2DecoderImpl* decoder, bool enforce_internal_framebuffer, bool internal) : decoder_(decoder) { - resolve_and_bind_ = (decoder_->offscreen_target_frame_buffer_.get() && - decoder_->IsOffscreenBufferMultisampled() && - (!decoder_->state_.bound_read_framebuffer.get() || - enforce_internal_framebuffer)); + resolve_and_bind_ = ( + decoder_->offscreen_target_frame_buffer_.get() && + decoder_->IsOffscreenBufferMultisampled() && + (!decoder_->framebuffer_state_.bound_read_framebuffer.get() || + enforce_internal_framebuffer)); if (!resolve_and_bind_) return; ScopedGLErrorSuppressor suppressor( - "ScopedResolvedFrameBufferBinder::ctor", decoder_); + "ScopedResolvedFrameBufferBinder::ctor", decoder_->GetErrorState()); glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, decoder_->offscreen_target_frame_buffer_->id()); GLuint targetid; @@ -1763,7 +1824,7 @@ ScopedResolvedFrameBufferBinder::ScopedResolvedFrameBufferBinder( new BackFramebuffer(decoder_)); decoder_->offscreen_resolved_frame_buffer_->Create(); decoder_->offscreen_resolved_color_texture_.reset( - new BackTexture(decoder_)); + new BackTexture(decoder->memory_tracker(), &decoder->state_)); decoder_->offscreen_resolved_color_texture_->Create(); DCHECK(decoder_->offscreen_saved_color_format_); @@ -1787,13 +1848,16 @@ ScopedResolvedFrameBufferBinder::ScopedResolvedFrameBufferBinder( const int width = decoder_->offscreen_size_.width(); const int height = decoder_->offscreen_size_.height(); glDisable(GL_SCISSOR_TEST); - if (GLES2Decoder::IsAngle()) { - glBlitFramebufferANGLE(0, 0, width, height, 0, 0, width, height, - GL_COLOR_BUFFER_BIT, GL_NEAREST); - } else { - glBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height, - GL_COLOR_BUFFER_BIT, GL_NEAREST); - } + decoder->BlitFramebufferHelper(0, + 0, + width, + height, + 0, + 0, + width, + height, + GL_COLOR_BUFFER_BIT, + GL_NEAREST); glBindFramebufferEXT(GL_FRAMEBUFFER, targetid); } @@ -1802,16 +1866,18 @@ ScopedResolvedFrameBufferBinder::~ScopedResolvedFrameBufferBinder() { return; ScopedGLErrorSuppressor suppressor( - "ScopedResolvedFrameBufferBinder::dtor", decoder_); + "ScopedResolvedFrameBufferBinder::dtor", decoder_->GetErrorState()); decoder_->RestoreCurrentFramebufferBindings(); if (decoder_->state_.enable_flags.scissor_test) { glEnable(GL_SCISSOR_TEST); } } -BackTexture::BackTexture(GLES2DecoderImpl* decoder) - : decoder_(decoder), - memory_tracker_(decoder->memory_tracker(), MemoryTracker::kUnmanaged), +BackTexture::BackTexture( + MemoryTracker* memory_tracker, + ContextState* state) + : memory_tracker_(memory_tracker, MemoryTracker::kUnmanaged), + state_(state), bytes_allocated_(0), id_(0) { } @@ -1824,10 +1890,11 @@ BackTexture::~BackTexture() { } void BackTexture::Create() { - ScopedGLErrorSuppressor suppressor("BackTexture::Create", decoder_); + ScopedGLErrorSuppressor suppressor("BackTexture::Create", + state_->GetErrorState()); Destroy(); glGenTextures(1, &id_); - ScopedTexture2DBinder binder(decoder_, id_); + ScopedTexture2DBinder binder(state_, id_); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -1849,8 +1916,9 @@ void BackTexture::Create() { bool BackTexture::AllocateStorage( const gfx::Size& size, GLenum format, bool zero) { DCHECK_NE(id_, 0u); - ScopedGLErrorSuppressor suppressor("BackTexture::AllocateStorage", decoder_); - ScopedTexture2DBinder binder(decoder_, id_); + ScopedGLErrorSuppressor suppressor("BackTexture::AllocateStorage", + state_->GetErrorState()); + ScopedTexture2DBinder binder(state_, id_); uint32 image_size = 0; GLES2Util::ComputeImageDataSizes( size.width(), size.height(), format, GL_UNSIGNED_BYTE, 8, &image_size, @@ -1889,8 +1957,9 @@ bool BackTexture::AllocateStorage( void BackTexture::Copy(const gfx::Size& size, GLenum format) { DCHECK_NE(id_, 0u); - ScopedGLErrorSuppressor suppressor("BackTexture::Copy", decoder_); - ScopedTexture2DBinder binder(decoder_, id_); + ScopedGLErrorSuppressor suppressor("BackTexture::Copy", + state_->GetErrorState()); + ScopedTexture2DBinder binder(state_, id_); glCopyTexImage2D(GL_TEXTURE_2D, 0, // level format, @@ -1902,7 +1971,8 @@ void BackTexture::Copy(const gfx::Size& size, GLenum format) { void BackTexture::Destroy() { if (id_ != 0) { - ScopedGLErrorSuppressor suppressor("BackTexture::Destroy", decoder_); + ScopedGLErrorSuppressor suppressor("BackTexture::Destroy", + state_->GetErrorState()); glDeleteTextures(1, &id_); id_ = 0; } @@ -1914,9 +1984,13 @@ void BackTexture::Invalidate() { id_ = 0; } -BackRenderbuffer::BackRenderbuffer(GLES2DecoderImpl* decoder) - : decoder_(decoder), - memory_tracker_(decoder->memory_tracker(), MemoryTracker::kUnmanaged), +BackRenderbuffer::BackRenderbuffer( + RenderbufferManager* renderbuffer_manager, + MemoryTracker* memory_tracker, + ContextState* state) + : renderbuffer_manager_(renderbuffer_manager), + memory_tracker_(memory_tracker, MemoryTracker::kUnmanaged), + state_(state), bytes_allocated_(0), id_(0) { } @@ -1929,19 +2003,22 @@ BackRenderbuffer::~BackRenderbuffer() { } void BackRenderbuffer::Create() { - ScopedGLErrorSuppressor suppressor("BackRenderbuffer::Create", decoder_); + ScopedGLErrorSuppressor suppressor("BackRenderbuffer::Create", + state_->GetErrorState()); Destroy(); glGenRenderbuffersEXT(1, &id_); } -bool BackRenderbuffer::AllocateStorage(const gfx::Size& size, GLenum format, +bool BackRenderbuffer::AllocateStorage(const FeatureInfo* feature_info, + const gfx::Size& size, + GLenum format, GLsizei samples) { ScopedGLErrorSuppressor suppressor( - "BackRenderbuffer::AllocateStorage", decoder_); - ScopedRenderBufferBinder binder(decoder_, id_); + "BackRenderbuffer::AllocateStorage", state_->GetErrorState()); + ScopedRenderBufferBinder binder(state_, id_); uint32 estimated_size = 0; - if (!decoder_->renderbuffer_manager()->ComputeEstimatedRenderbufferSize( + if (!renderbuffer_manager_->ComputeEstimatedRenderbufferSize( size.width(), size.height(), samples, format, &estimated_size)) { return false; } @@ -1956,24 +2033,19 @@ bool BackRenderbuffer::AllocateStorage(const gfx::Size& size, GLenum format, size.width(), size.height()); } else { - if (GLES2Decoder::IsAngle()) { - glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, - samples, - format, - size.width(), - size.height()); - } else { - glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, - samples, - format, - size.width(), - size.height()); - } + GLES2DecoderImpl::RenderbufferStorageMultisampleHelper(feature_info, + GL_RENDERBUFFER, + samples, + format, + size.width(), + size.height()); } bool success = glGetError() == GL_NO_ERROR; if (success) { + // Mark the previously allocated bytes as free. memory_tracker_.TrackMemFree(bytes_allocated_); bytes_allocated_ = estimated_size; + // Track the newly allocated bytes. memory_tracker_.TrackMemAlloc(bytes_allocated_); } return success; @@ -1981,7 +2053,8 @@ bool BackRenderbuffer::AllocateStorage(const gfx::Size& size, GLenum format, void BackRenderbuffer::Destroy() { if (id_ != 0) { - ScopedGLErrorSuppressor suppressor("BackRenderbuffer::Destroy", decoder_); + ScopedGLErrorSuppressor suppressor("BackRenderbuffer::Destroy", + state_->GetErrorState()); glDeleteRenderbuffersEXT(1, &id_); id_ = 0; } @@ -2006,7 +2079,8 @@ BackFramebuffer::~BackFramebuffer() { } void BackFramebuffer::Create() { - ScopedGLErrorSuppressor suppressor("BackFramebuffer::Create", decoder_); + ScopedGLErrorSuppressor suppressor("BackFramebuffer::Create", + decoder_->GetErrorState()); Destroy(); glGenFramebuffersEXT(1, &id_); } @@ -2014,7 +2088,7 @@ void BackFramebuffer::Create() { void BackFramebuffer::AttachRenderTexture(BackTexture* texture) { DCHECK_NE(id_, 0u); ScopedGLErrorSuppressor suppressor( - "BackFramebuffer::AttachRenderTexture", decoder_); + "BackFramebuffer::AttachRenderTexture", decoder_->GetErrorState()); ScopedFrameBufferBinder binder(decoder_, id_); GLuint attach_id = texture ? texture->id() : 0; glFramebufferTexture2DEXT(GL_FRAMEBUFFER, @@ -2028,7 +2102,7 @@ void BackFramebuffer::AttachRenderBuffer(GLenum target, BackRenderbuffer* render_buffer) { DCHECK_NE(id_, 0u); ScopedGLErrorSuppressor suppressor( - "BackFramebuffer::AttachRenderBuffer", decoder_); + "BackFramebuffer::AttachRenderBuffer", decoder_->GetErrorState()); ScopedFrameBufferBinder binder(decoder_, id_); GLuint attach_id = render_buffer ? render_buffer->id() : 0; glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, @@ -2039,7 +2113,8 @@ void BackFramebuffer::AttachRenderBuffer(GLenum target, void BackFramebuffer::Destroy() { if (id_ != 0) { - ScopedGLErrorSuppressor suppressor("BackFramebuffer::Destroy", decoder_); + ScopedGLErrorSuppressor suppressor("BackFramebuffer::Destroy", + decoder_->GetErrorState()); glDeleteFramebuffersEXT(1, &id_); id_ = 0; } @@ -2051,7 +2126,8 @@ void BackFramebuffer::Invalidate() { GLenum BackFramebuffer::CheckStatus() { DCHECK_NE(id_, 0u); - ScopedGLErrorSuppressor suppressor("BackFramebuffer::CheckStatus", decoder_); + ScopedGLErrorSuppressor suppressor("BackFramebuffer::CheckStatus", + decoder_->GetErrorState()); ScopedFrameBufferBinder binder(decoder_, id_); return glCheckFramebufferStatusEXT(GL_FRAMEBUFFER); } @@ -2100,6 +2176,9 @@ GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group) switches::kEnableGPUServiceLoggingGPU)), viewport_max_width_(0), viewport_max_height_(0), + texture_state_(group_->feature_info() + ->workarounds() + .texsubimage2d_faster_than_teximage2d), validation_texture_(0), validation_fbo_multisample_(0), validation_fbo_(0) { @@ -2120,11 +2199,6 @@ GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group) switches::kDisableGLSLTranslator)) { use_shader_translator_ = false; } - - // TODO(gman): Consider setting this based on GPU and/or driver. - if (IsAngle()) { - texture_state_.teximage2d_faster_than_texsubimage2d = false; - } } GLES2DecoderImpl::~GLES2DecoderImpl() { @@ -2164,6 +2238,19 @@ bool GLES2DecoderImpl::Initialize( context_ = context; surface_ = surface; + ContextCreationAttribHelper attrib_parser; + if (!attrib_parser.Parse(attribs)) + return false; + + // If the failIfMajorPerformanceCaveat context creation attribute was true + // and we are using a software renderer, fail. + if (attrib_parser.fail_if_major_perf_caveat_ && + feature_info_->feature_flags().is_swiftshader) { + group_ = NULL; // Must not destroy ContextGroup if it is not initialized. + Destroy(true); + return false; + } + if (!group_->Initialize(this, disallowed_features)) { LOG(ERROR) << "GpuScheduler::InitializeCommon failed because group " << "failed to initialize."; @@ -2226,10 +2313,6 @@ bool GLES2DecoderImpl::Initialize( glActiveTexture(GL_TEXTURE0); CHECK_GL_ERROR(); - ContextCreationAttribHelper attrib_parser; - if (!attrib_parser.Parse(attribs)) - return false; - if (offscreen) { if (attrib_parser.samples_ > 0 && attrib_parser.sample_buffers_ > 0 && features().chromium_framebuffer_multisample) { @@ -2263,7 +2346,7 @@ bool GLES2DecoderImpl::Initialize( // ANGLE only supports packed depth/stencil formats, so use it if it is // available. const bool depth24_stencil8_supported = - context_->HasExtension("GL_OES_packed_depth_stencil"); + feature_info_->feature_flags().packed_depth24_stencil8; VLOG(1) << "GL_OES_packed_depth_stencil " << (depth24_stencil8_supported ? "" : "not ") << "supported."; if ((attrib_parser.depth_size_ > 0 || attrib_parser.stencil_size_ > 0) && @@ -2286,7 +2369,7 @@ bool GLES2DecoderImpl::Initialize( // it's available, as some desktop GL drivers don't support any non-packed // formats for depth attachments. const bool depth24_stencil8_supported = - context_->HasExtension("GL_EXT_packed_depth_stencil"); + feature_info_->feature_flags().packed_depth24_stencil8; VLOG(1) << "GL_EXT_packed_depth_stencil " << (depth24_stencil8_supported ? "" : "not ") << "supported."; @@ -2314,15 +2397,19 @@ bool GLES2DecoderImpl::Initialize( // attached to the offscreen frame buffer. The render buffer has more // limited formats available to it, but the texture can't do multisampling. if (IsOffscreenBufferMultisampled()) { - offscreen_target_color_render_buffer_.reset(new BackRenderbuffer(this)); + offscreen_target_color_render_buffer_.reset(new BackRenderbuffer( + renderbuffer_manager(), memory_tracker(), &state_)); offscreen_target_color_render_buffer_->Create(); } else { - offscreen_target_color_texture_.reset(new BackTexture(this)); + offscreen_target_color_texture_.reset(new BackTexture( + memory_tracker(), &state_)); offscreen_target_color_texture_->Create(); } - offscreen_target_depth_render_buffer_.reset(new BackRenderbuffer(this)); + offscreen_target_depth_render_buffer_.reset(new BackRenderbuffer( + renderbuffer_manager(), memory_tracker(), &state_)); offscreen_target_depth_render_buffer_->Create(); - offscreen_target_stencil_render_buffer_.reset(new BackRenderbuffer(this)); + offscreen_target_stencil_render_buffer_.reset(new BackRenderbuffer( + renderbuffer_manager(), memory_tracker(), &state_)); offscreen_target_stencil_render_buffer_->Create(); // Create the saved offscreen texture. The target frame buffer is copied @@ -2330,7 +2417,8 @@ bool GLES2DecoderImpl::Initialize( offscreen_saved_frame_buffer_.reset(new BackFramebuffer(this)); offscreen_saved_frame_buffer_->Create(); // - offscreen_saved_color_texture_.reset(new BackTexture(this)); + offscreen_saved_color_texture_.reset(new BackTexture( + memory_tracker(), &state_)); offscreen_saved_color_texture_->Create(); // Allocate the render buffers at their initial size and check the status @@ -2442,6 +2530,10 @@ bool GLES2DecoderImpl::Initialize( context_->SetUnbindFboOnMakeCurrent(); } + if (feature_info_->workarounds().release_image_after_use) { + image_manager()->SetReleaseAfterUse(); + } + // Only compositor contexts are known to use only the subset of GL // that can be safely migrated between the iGPU and the dGPU. Mark // those contexts as safe to forcibly transition between the GPUs. @@ -2453,9 +2545,46 @@ bool GLES2DecoderImpl::Initialize( AsyncPixelTransferManager::Create(context.get())); async_pixel_transfer_manager_->Initialize(texture_manager()); + framebuffer_manager()->AddObserver(this); + return true; } +Capabilities GLES2DecoderImpl::GetCapabilities() { + DCHECK(initialized()); + + Capabilities caps; + + caps.fast_npot_mo8_textures = + feature_info_->workarounds().enable_chromium_fast_npot_mo8_textures; + caps.egl_image_external = + feature_info_->feature_flags().oes_egl_image_external; + caps.texture_format_bgra8888 = + feature_info_->feature_flags().ext_texture_format_bgra8888; + caps.texture_format_etc1 = + feature_info_->feature_flags().oes_compressed_etc1_rgb8_texture; + caps.texture_rectangle = feature_info_->feature_flags().arb_texture_rectangle; + caps.texture_usage = feature_info_->feature_flags().angle_texture_usage; + caps.texture_storage = feature_info_->feature_flags().ext_texture_storage; + caps.discard_framebuffer = + feature_info_->feature_flags().ext_discard_framebuffer; + +#if defined(OS_MACOSX) + // This is unconditionally true on mac, no need to test for it at runtime. + caps.iosurface = true; +#endif + + // TODO(boliu): Expose this directly from GLSurface. + std::vector<std::string> extension_list; + base::SplitString(surface_->GetExtensions(), ' ', &extension_list); + std::set<std::string> extension_set(extension_list.begin(), + extension_list.end()); + caps.post_sub_buffer = + extension_set.count("GL_CHROMIUM_post_sub_buffer") > 0; + + return caps; +} + void GLES2DecoderImpl::UpdateCapabilities() { util_.set_num_compressed_texture_formats( validators_->compressed_texture_format.GetValues().size()); @@ -2531,6 +2660,8 @@ bool GLES2DecoderImpl::InitializeShaderTranslator() { driver_bug_workarounds |= SH_EMULATE_BUILT_IN_FUNCTIONS; if (workarounds().init_gl_position_in_vertex_shader) driver_bug_workarounds |= SH_INIT_GL_POSITION; + if (workarounds().unfold_short_circuit_as_ternary_operation) + driver_bug_workarounds |= SH_UNFOLD_SHORT_CIRCUIT; ShaderTranslatorCache* cache = ShaderTranslatorCache::GetInstance(); vertex_translator_ = cache->GetTranslator( @@ -2636,15 +2767,15 @@ void GLES2DecoderImpl::DeleteFramebuffersHelper( Framebuffer* framebuffer = GetFramebuffer(client_ids[ii]); if (framebuffer && !framebuffer->IsDeleted()) { - if (framebuffer == state_.bound_draw_framebuffer.get()) { - state_.bound_draw_framebuffer = NULL; + if (framebuffer == framebuffer_state_.bound_draw_framebuffer.get()) { + framebuffer_state_.bound_draw_framebuffer = NULL; framebuffer_state_.clear_state_dirty = true; GLenum target = supports_separate_framebuffer_binds ? GL_DRAW_FRAMEBUFFER_EXT : GL_FRAMEBUFFER; glBindFramebufferEXT(target, GetBackbufferServiceId()); } - if (framebuffer == state_.bound_read_framebuffer.get()) { - state_.bound_read_framebuffer = NULL; + if (framebuffer == framebuffer_state_.bound_read_framebuffer.get()) { + framebuffer_state_.bound_read_framebuffer = NULL; GLenum target = supports_separate_framebuffer_binds ? GL_READ_FRAMEBUFFER_EXT : GL_FRAMEBUFFER; glBindFramebufferEXT(target, GetBackbufferServiceId()); @@ -2668,17 +2799,17 @@ void GLES2DecoderImpl::DeleteRenderbuffersHelper( } // Unbind from current framebuffers. if (supports_separate_framebuffer_binds) { - if (state_.bound_read_framebuffer.get()) { - state_.bound_read_framebuffer + if (framebuffer_state_.bound_read_framebuffer.get()) { + framebuffer_state_.bound_read_framebuffer ->UnbindRenderbuffer(GL_READ_FRAMEBUFFER_EXT, renderbuffer); } - if (state_.bound_draw_framebuffer.get()) { - state_.bound_draw_framebuffer + if (framebuffer_state_.bound_draw_framebuffer.get()) { + framebuffer_state_.bound_draw_framebuffer ->UnbindRenderbuffer(GL_DRAW_FRAMEBUFFER_EXT, renderbuffer); } } else { - if (state_.bound_draw_framebuffer.get()) { - state_.bound_draw_framebuffer + if (framebuffer_state_.bound_draw_framebuffer.get()) { + framebuffer_state_.bound_draw_framebuffer ->UnbindRenderbuffer(GL_FRAMEBUFFER, renderbuffer); } } @@ -2705,17 +2836,17 @@ void GLES2DecoderImpl::DeleteTexturesHelper( } // Unbind from current framebuffers. if (supports_separate_framebuffer_binds) { - if (state_.bound_read_framebuffer.get()) { - state_.bound_read_framebuffer + if (framebuffer_state_.bound_read_framebuffer.get()) { + framebuffer_state_.bound_read_framebuffer ->UnbindTexture(GL_READ_FRAMEBUFFER_EXT, texture_ref); } - if (state_.bound_draw_framebuffer.get()) { - state_.bound_draw_framebuffer + if (framebuffer_state_.bound_draw_framebuffer.get()) { + framebuffer_state_.bound_draw_framebuffer ->UnbindTexture(GL_DRAW_FRAMEBUFFER_EXT, texture_ref); } } else { - if (state_.bound_draw_framebuffer.get()) { - state_.bound_draw_framebuffer + if (framebuffer_state_.bound_draw_framebuffer.get()) { + framebuffer_state_.bound_draw_framebuffer ->UnbindTexture(GL_FRAMEBUFFER, texture_ref); } } @@ -2733,10 +2864,10 @@ void GLES2DecoderImpl::DeleteTexturesHelper( // } // anonymous namespace bool GLES2DecoderImpl::MakeCurrent() { - if (!context_.get() || !context_->MakeCurrent(surface_.get())) + if (!context_.get()) return false; - if (WasContextLost()) { + if (!context_->MakeCurrent(surface_.get()) || WasContextLost()) { LOG(ERROR) << " GLES2DecoderImpl: Context lost during MakeCurrent."; // Some D3D drivers cannot recover from device lost in the GPU process @@ -2782,13 +2913,6 @@ void GLES2DecoderImpl::ReleaseCurrent() { context_->ReleaseCurrent(surface_.get()); } -void GLES2DecoderImpl::RestoreCurrentRenderbufferBindings() { - Renderbuffer* renderbuffer = - GetRenderbufferInfoForTarget(GL_RENDERBUFFER); - glBindRenderbufferEXT( - GL_RENDERBUFFER, renderbuffer ? renderbuffer->service_id() : 0); -} - static void RebindCurrentFramebuffer( GLenum target, Framebuffer* framebuffer, @@ -2808,34 +2932,21 @@ void GLES2DecoderImpl::RestoreCurrentFramebufferBindings() { if (!features().chromium_framebuffer_multisample) { RebindCurrentFramebuffer( GL_FRAMEBUFFER, - state_.bound_draw_framebuffer.get(), + framebuffer_state_.bound_draw_framebuffer.get(), GetBackbufferServiceId()); } else { RebindCurrentFramebuffer( GL_READ_FRAMEBUFFER_EXT, - state_.bound_read_framebuffer.get(), + framebuffer_state_.bound_read_framebuffer.get(), GetBackbufferServiceId()); RebindCurrentFramebuffer( GL_DRAW_FRAMEBUFFER_EXT, - state_.bound_draw_framebuffer.get(), + framebuffer_state_.bound_draw_framebuffer.get(), GetBackbufferServiceId()); } OnFboChanged(); } -void GLES2DecoderImpl::RestoreCurrentTexture2DBindings() { - TextureUnit& info = state_.texture_units[0]; - GLuint last_id; - if (info.bound_texture_2d.get()) { - last_id = info.bound_texture_2d->service_id(); - } else { - last_id = 0; - } - - glBindTexture(GL_TEXTURE_2D, last_id); - glActiveTexture(GL_TEXTURE0 + state_.active_texture_unit); -} - bool GLES2DecoderImpl::CheckFramebufferValid( Framebuffer* framebuffer, GLenum target, const char* func_name) { @@ -2902,17 +3013,18 @@ bool GLES2DecoderImpl::CheckFramebufferValid( bool GLES2DecoderImpl::CheckBoundFramebuffersValid(const char* func_name) { if (!features().chromium_framebuffer_multisample) { bool valid = CheckFramebufferValid( - state_.bound_draw_framebuffer.get(), GL_FRAMEBUFFER_EXT, func_name); + framebuffer_state_.bound_draw_framebuffer.get(), GL_FRAMEBUFFER_EXT, + func_name); if (valid) OnUseFramebuffer(); return valid; } - return CheckFramebufferValid(state_.bound_draw_framebuffer.get(), + return CheckFramebufferValid(framebuffer_state_.bound_draw_framebuffer.get(), GL_DRAW_FRAMEBUFFER_EXT, func_name) && - CheckFramebufferValid(state_.bound_read_framebuffer.get(), + CheckFramebufferValid(framebuffer_state_.bound_read_framebuffer.get(), GL_READ_FRAMEBUFFER_EXT, func_name); } @@ -2934,6 +3046,16 @@ gfx::Size GLES2DecoderImpl::GetBoundReadFrameBufferSize() { } } +GLenum GLES2DecoderImpl::GetBoundReadFrameBufferTextureType() { + Framebuffer* framebuffer = + GetFramebufferInfoForTarget(GL_READ_FRAMEBUFFER_EXT); + if (framebuffer != NULL) { + return framebuffer->GetColorAttachmentTextureType(); + } else { + return GL_UNSIGNED_BYTE; + } +} + GLenum GLES2DecoderImpl::GetBoundReadFrameBufferInternalFormat() { Framebuffer* framebuffer = GetFramebufferInfoForTarget(GL_READ_FRAMEBUFFER_EXT); @@ -3081,8 +3203,8 @@ void GLES2DecoderImpl::Destroy(bool have_context) { state_.texture_units.clear(); state_.bound_array_buffer = NULL; state_.current_query = NULL; - state_.bound_read_framebuffer = NULL; - state_.bound_draw_framebuffer = NULL; + framebuffer_state_.bound_read_framebuffer = NULL; + framebuffer_state_.bound_draw_framebuffer = NULL; state_.bound_renderbuffer = NULL; if (offscreen_saved_color_texture_info_.get()) { @@ -3189,6 +3311,7 @@ void GLES2DecoderImpl::Destroy(bool have_context) { async_pixel_transfer_manager_.reset(); if (group_.get()) { + framebuffer_manager()->RemoveObserver(this); group_->Destroy(this, have_context); group_ = NULL; } @@ -3285,7 +3408,7 @@ bool GLES2DecoderImpl::ResizeOffscreenFrameBuffer(const gfx::Size& size) { DCHECK(offscreen_target_color_format_); if (IsOffscreenBufferMultisampled()) { if (!offscreen_target_color_render_buffer_->AllocateStorage( - offscreen_size_, offscreen_target_color_format_, + feature_info_, offscreen_size_, offscreen_target_color_format_, offscreen_target_samples_)) { LOG(ERROR) << "GLES2DecoderImpl::ResizeOffscreenFrameBuffer failed " << "to allocate storage for offscreen target color buffer."; @@ -3301,7 +3424,7 @@ bool GLES2DecoderImpl::ResizeOffscreenFrameBuffer(const gfx::Size& size) { } if (offscreen_target_depth_format_ && !offscreen_target_depth_render_buffer_->AllocateStorage( - offscreen_size_, offscreen_target_depth_format_, + feature_info_, offscreen_size_, offscreen_target_depth_format_, offscreen_target_samples_)) { LOG(ERROR) << "GLES2DecoderImpl::ResizeOffscreenFrameBuffer failed " << "to allocate storage for offscreen target depth buffer."; @@ -3309,7 +3432,7 @@ bool GLES2DecoderImpl::ResizeOffscreenFrameBuffer(const gfx::Size& size) { } if (offscreen_target_stencil_format_ && !offscreen_target_stencil_render_buffer_->AllocateStorage( - offscreen_size_, offscreen_target_stencil_format_, + feature_info_, offscreen_size_, offscreen_target_stencil_format_, offscreen_target_samples_)) { LOG(ERROR) << "GLES2DecoderImpl::ResizeOffscreenFrameBuffer failed " << "to allocate storage for offscreen target stencil buffer."; @@ -3434,7 +3557,7 @@ error::Error GLES2DecoderImpl::DoCommand( error::Error result = error::kNoError; if (log_commands()) { // TODO(notme): Change this to a LOG/VLOG that works in release. Tried - // LOG(INFO), tried VLOG(1), no luck. + // VLOG(1), no luck. LOG(ERROR) << "[" << logger_.GetLogPrefix() << "]" << "cmd: " << GetCommandName(command); } @@ -3648,15 +3771,16 @@ void GLES2DecoderImpl::RestoreState() const { } void GLES2DecoderImpl::RestoreFramebufferBindings() const { - GLuint service_id = state_.bound_draw_framebuffer.get() - ? state_.bound_draw_framebuffer->service_id() - : GetBackbufferServiceId(); + GLuint service_id = + framebuffer_state_.bound_draw_framebuffer.get() + ? framebuffer_state_.bound_draw_framebuffer->service_id() + : GetBackbufferServiceId(); if (!features().chromium_framebuffer_multisample) { glBindFramebufferEXT(GL_FRAMEBUFFER, service_id); } else { glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, service_id); - service_id = state_.bound_read_framebuffer.get() - ? state_.bound_read_framebuffer->service_id() + service_id = framebuffer_state_.bound_read_framebuffer.get() + ? framebuffer_state_.bound_read_framebuffer->service_id() : GetBackbufferServiceId(); glBindFramebufferEXT(GL_READ_FRAMEBUFFER, service_id); } @@ -3729,10 +3853,10 @@ void GLES2DecoderImpl::DoBindFramebuffer(GLenum target, GLuint client_id) { LogClientServiceForInfo(framebuffer, client_id, "glBindFramebuffer"); if (target == GL_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER_EXT) { - state_.bound_draw_framebuffer = framebuffer; + framebuffer_state_.bound_draw_framebuffer = framebuffer; } if (target == GL_FRAMEBUFFER || target == GL_READ_FRAMEBUFFER_EXT) { - state_.bound_read_framebuffer = framebuffer; + framebuffer_state_.bound_read_framebuffer = framebuffer; } framebuffer_state_.clear_state_dirty = true; @@ -3860,6 +3984,13 @@ void GLES2DecoderImpl::DoDisableVertexAttribArray(GLuint index) { void GLES2DecoderImpl::DoDiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum* attachments) { + if (!features().ext_discard_framebuffer) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, + "glDiscardFramebufferEXT", + "function not available"); + return; + } + Framebuffer* framebuffer = GetFramebufferInfoForTarget(GL_FRAMEBUFFER); @@ -3993,13 +4124,16 @@ bool GLES2DecoderImpl::GetHelper( case GL_IMPLEMENTATION_COLOR_READ_FORMAT: *num_written = 1; if (params) { - *params = GL_RGBA; // We don't support other formats. + *params = GLES2Util::GetPreferredGLReadPixelsFormat( + GetBoundReadFrameBufferInternalFormat()); } return true; case GL_IMPLEMENTATION_COLOR_READ_TYPE: *num_written = 1; if (params) { - *params = GL_UNSIGNED_BYTE; // We don't support other types. + *params = GLES2Util::GetPreferredGLReadPixelsType( + GetBoundReadFrameBufferInternalFormat(), + GetBoundReadFrameBufferTextureType()); } return true; case GL_MAX_FRAGMENT_UNIFORM_VECTORS: @@ -4426,21 +4560,6 @@ error::Error GLES2DecoderImpl::HandleBindAttribLocation( return error::kNoError; } -error::Error GLES2DecoderImpl::HandleBindAttribLocationImmediate( - uint32 immediate_data_size, const cmds::BindAttribLocationImmediate& c) { - GLuint program = static_cast<GLuint>(c.program); - GLuint index = static_cast<GLuint>(c.index); - uint32 name_size = c.data_size; - const char* name = GetImmediateDataAs<const char*>( - c, name_size, immediate_data_size); - if (name == NULL) { - return error::kOutOfBounds; - } - String name_str(name, name_size); - DoBindAttribLocation(program, index, name_str.c_str()); - return error::kNoError; -} - error::Error GLES2DecoderImpl::HandleBindAttribLocationBucket( uint32 immediate_data_size, const cmds::BindAttribLocationBucket& c) { GLuint program = static_cast<GLuint>(c.program); @@ -4506,22 +4625,6 @@ error::Error GLES2DecoderImpl::HandleBindUniformLocationCHROMIUM( return error::kNoError; } -error::Error GLES2DecoderImpl::HandleBindUniformLocationCHROMIUMImmediate( - uint32 immediate_data_size, - const cmds::BindUniformLocationCHROMIUMImmediate& c) { - GLuint program = static_cast<GLuint>(c.program); - GLint location = static_cast<GLint>(c.location); - uint32 name_size = c.data_size; - const char* name = GetImmediateDataAs<const char*>( - c, name_size, immediate_data_size); - if (name == NULL) { - return error::kOutOfBounds; - } - String name_str(name, name_size); - DoBindUniformLocationCHROMIUM(program, location, name_str.c_str()); - return error::kNoError; -} - error::Error GLES2DecoderImpl::HandleBindUniformLocationCHROMIUMBucket( uint32 immediate_data_size, const cmds::BindUniformLocationCHROMIUMBucket& c) { @@ -4714,7 +4817,7 @@ void GLES2DecoderImpl::DoFramebufferRenderbuffer( if (error == GL_NO_ERROR) { framebuffer->AttachRenderbuffer(attachment, renderbuffer); } - if (framebuffer == state_.bound_draw_framebuffer.get()) { + if (framebuffer == framebuffer_state_.bound_draw_framebuffer.get()) { framebuffer_state_.clear_state_dirty = true; } OnFboChanged(); @@ -4881,6 +4984,9 @@ void GLES2DecoderImpl::DoFramebufferTexture2DCommon( return; } + if (texture_ref) + DoWillUseTexImageIfNeeded(texture_ref->texture(), textarget); + LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER(name); if (0 == samples) { glFramebufferTexture2DEXT(target, attachment, textarget, service_id, level); @@ -4898,9 +5004,13 @@ void GLES2DecoderImpl::DoFramebufferTexture2DCommon( framebuffer->AttachTexture(attachment, texture_ref, textarget, level, samples); } - if (framebuffer == state_.bound_draw_framebuffer.get()) { + if (framebuffer == framebuffer_state_.bound_draw_framebuffer.get()) { framebuffer_state_.clear_state_dirty = true; } + + if (texture_ref) + DoDidUseTexImageIfNeeded(texture_ref->texture(), textarget); + OnFboChanged(); } @@ -4960,7 +5070,7 @@ void GLES2DecoderImpl::DoGetRenderbufferParameteriv( } } -void GLES2DecoderImpl::DoBlitFramebufferEXT( +void GLES2DecoderImpl::DoBlitFramebufferCHROMIUM( GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { @@ -4968,49 +5078,75 @@ void GLES2DecoderImpl::DoBlitFramebufferEXT( if (!features().chromium_framebuffer_multisample) { LOCAL_SET_GL_ERROR( GL_INVALID_OPERATION, - "glBlitFramebufferEXT", "function not available"); + "glBlitFramebufferCHROMIUM", "function not available"); + return; } - if (!CheckBoundFramebuffersValid("glBlitFramebufferEXT")) { + if (!CheckBoundFramebuffersValid("glBlitFramebufferCHROMIUM")) { return; } glDisable(GL_SCISSOR_TEST); - if (IsAngle()) { + BlitFramebufferHelper( + srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + EnableDisable(GL_SCISSOR_TEST, state_.enable_flags.scissor_test); +} + +void GLES2DecoderImpl::RenderbufferStorageMultisampleHelper( + const FeatureInfo* feature_info, + GLenum target, + GLsizei samples, + GLenum internal_format, + GLsizei width, + GLsizei height) { + // TODO(sievers): This could be resolved at the GL binding level, but the + // binding process is currently a bit too 'brute force'. + if (feature_info->feature_flags().is_angle) { + glRenderbufferStorageMultisampleANGLE( + target, samples, internal_format, width, height); + } else if (feature_info->feature_flags().use_core_framebuffer_multisample) { + glRenderbufferStorageMultisample( + target, samples, internal_format, width, height); + } else { + glRenderbufferStorageMultisampleEXT( + target, samples, internal_format, width, height); + } +} + +void GLES2DecoderImpl::BlitFramebufferHelper(GLint srcX0, + GLint srcY0, + GLint srcX1, + GLint srcY1, + GLint dstX0, + GLint dstY0, + GLint dstX1, + GLint dstY1, + GLbitfield mask, + GLenum filter) { + // TODO(sievers): This could be resolved at the GL binding level, but the + // binding process is currently a bit too 'brute force'. + if (feature_info_->feature_flags().is_angle) { glBlitFramebufferANGLE( srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + } else if (feature_info_->feature_flags().use_core_framebuffer_multisample) { + glBlitFramebuffer( + srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); } else { glBlitFramebufferEXT( srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); } - EnableDisable(GL_SCISSOR_TEST, state_.enable_flags.scissor_test); } -void GLES2DecoderImpl::DoRenderbufferStorageMultisample( - GLenum target, GLsizei samples, GLenum internalformat, - GLsizei width, GLsizei height) { - if (!features().chromium_framebuffer_multisample && - !features().multisampled_render_to_texture) { - LOCAL_SET_GL_ERROR( - GL_INVALID_OPERATION, - "glRenderbufferStorageMultisample", "function not available"); - return; - } - - Renderbuffer* renderbuffer = - GetRenderbufferInfoForTarget(GL_RENDERBUFFER); - if (!renderbuffer) { - LOCAL_SET_GL_ERROR( - GL_INVALID_OPERATION, - "glRenderbufferStorageMultisample", "no renderbuffer bound"); - return; - } - +bool GLES2DecoderImpl::ValidateRenderbufferStorageMultisample( + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height) { if (samples > renderbuffer_manager()->max_samples()) { LOCAL_SET_GL_ERROR( GL_INVALID_VALUE, "glRenderbufferStorageMultisample", "samples too large"); - return; + return false; } if (width > renderbuffer_manager()->max_renderbuffer_size() || @@ -5018,7 +5154,7 @@ void GLES2DecoderImpl::DoRenderbufferStorageMultisample( LOCAL_SET_GL_ERROR( GL_INVALID_VALUE, "glRenderbufferStorageMultisample", "dimensions too large"); - return; + return false; } uint32 estimated_size = 0; @@ -5027,31 +5163,51 @@ void GLES2DecoderImpl::DoRenderbufferStorageMultisample( LOCAL_SET_GL_ERROR( GL_OUT_OF_MEMORY, "glRenderbufferStorageMultsample", "dimensions too large"); - return; + return false; } if (!EnsureGPUMemoryAvailable(estimated_size)) { LOCAL_SET_GL_ERROR( GL_OUT_OF_MEMORY, "glRenderbufferStorageMultsample", "out of memory"); + return false; + } + + return true; +} + +void GLES2DecoderImpl::DoRenderbufferStorageMultisampleCHROMIUM( + GLenum target, GLsizei samples, GLenum internalformat, + GLsizei width, GLsizei height) { + if (!features().chromium_framebuffer_multisample) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, + "glRenderbufferStorageMultisampleCHROMIUM", + "function not available"); + return; + } + + Renderbuffer* renderbuffer = GetRenderbufferInfoForTarget(GL_RENDERBUFFER); + if (!renderbuffer) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, + "glRenderbufferStorageMultisampleCHROMIUM", + "no renderbuffer bound"); + return; + } + + if (!ValidateRenderbufferStorageMultisample( + samples, internalformat, width, height)) { return; } GLenum impl_format = renderbuffer_manager()->InternalRenderbufferFormatToImplFormat( internalformat); - LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glRenderbufferStorageMultisample"); - if (IsAngle()) { - glRenderbufferStorageMultisampleANGLE( - target, samples, impl_format, width, height); - } else if (features().use_img_for_multisampled_render_to_texture) { - glRenderbufferStorageMultisampleIMG( - target, samples, impl_format, width, height); - } else { - glRenderbufferStorageMultisampleEXT( - target, samples, impl_format, width, height); - } - GLenum error = LOCAL_PEEK_GL_ERROR("glRenderbufferStorageMultisample"); + LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER( + "glRenderbufferStorageMultisampleCHROMIUM"); + RenderbufferStorageMultisampleHelper( + feature_info_, target, samples, impl_format, width, height); + GLenum error = + LOCAL_PEEK_GL_ERROR("glRenderbufferStorageMultisampleCHROMIUM"); if (error == GL_NO_ERROR) { if (workarounds().validate_multisample_buffer_allocation) { @@ -5059,7 +5215,7 @@ void GLES2DecoderImpl::DoRenderbufferStorageMultisample( renderbuffer->service_id(), impl_format)) { LOCAL_SET_GL_ERROR( GL_OUT_OF_MEMORY, - "glRenderbufferStorageMultisample", "out of memory"); + "glRenderbufferStorageMultisampleCHROMIUM", "out of memory"); return; } } @@ -5072,6 +5228,51 @@ void GLES2DecoderImpl::DoRenderbufferStorageMultisample( } } +// This is the handler for multisampled_render_to_texture extensions. +void GLES2DecoderImpl::DoRenderbufferStorageMultisampleEXT( + GLenum target, GLsizei samples, GLenum internalformat, + GLsizei width, GLsizei height) { + if (!features().multisampled_render_to_texture) { + LOCAL_SET_GL_ERROR( + GL_INVALID_OPERATION, + "glRenderbufferStorageMultisampleEXT", "function not available"); + return; + } + + Renderbuffer* renderbuffer = GetRenderbufferInfoForTarget(GL_RENDERBUFFER); + if (!renderbuffer) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, + "glRenderbufferStorageMultisampleEXT", + "no renderbuffer bound"); + return; + } + + if (!ValidateRenderbufferStorageMultisample( + samples, internalformat, width, height)) { + return; + } + + GLenum impl_format = + renderbuffer_manager()->InternalRenderbufferFormatToImplFormat( + internalformat); + LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glRenderbufferStorageMultisampleEXT"); + if (features().use_img_for_multisampled_render_to_texture) { + glRenderbufferStorageMultisampleIMG( + target, samples, impl_format, width, height); + } else { + glRenderbufferStorageMultisampleEXT( + target, samples, impl_format, width, height); + } + GLenum error = LOCAL_PEEK_GL_ERROR("glRenderbufferStorageMultisampleEXT"); + if (error == GL_NO_ERROR) { + // TODO(gman): If renderbuffers tracked which framebuffers they were + // attached to we could just mark those framebuffers as not complete. + framebuffer_manager()->IncFramebufferStateChangeCount(); + renderbuffer_manager()->SetInfo( + renderbuffer, samples, internalformat, width, height); + } +} + // This function validates the allocation of a multisampled renderbuffer // by clearing it to a key color, blitting the contents to a texture, and // reading back the color to ensure it matches the key. @@ -5144,7 +5345,8 @@ bool GLES2DecoderImpl::VerifyMultisampleRenderbufferIntegrity( glBindFramebufferEXT(GL_READ_FRAMEBUFFER, validation_fbo_multisample_); glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, validation_fbo_); - glBlitFramebufferEXT(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST); + BlitFramebufferHelper( + 0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST); // Read a pixel from the buffer. glBindFramebufferEXT(GL_FRAMEBUFFER, validation_fbo_); @@ -5239,13 +5441,14 @@ void GLES2DecoderImpl::DoLinkProgram(GLuint program_id) { if (program->Link(shader_manager(), vertex_translator, fragment_translator, - feature_info_.get(), + workarounds().count_all_in_varyings_packing ? + Program::kCountAll : Program::kCountOnlyStaticallyUsed, shader_cache_callback_)) { if (program == state_.current_program.get()) { - if (workarounds().use_current_program_after_successful_link) { + if (workarounds().use_current_program_after_successful_link) glUseProgram(program->service_id()); - } - program_manager()->ClearUniforms(program); + if (workarounds().clear_uniforms_before_first_program_use) + program_manager()->ClearUniforms(program); } } }; @@ -5711,6 +5914,8 @@ void GLES2DecoderImpl::DoUseProgram(GLuint program_id) { glUseProgram(service_id); if (state_.current_program.get()) { program_manager()->UseProgram(state_.current_program.get()); + if (workarounds().clear_uniforms_before_first_program_use) + program_manager()->ClearUniforms(program); } } @@ -5738,11 +5943,49 @@ void GLES2DecoderImpl::UpdateStreamTextureIfNeeded(Texture* texture, } } +void GLES2DecoderImpl::DoWillUseTexImageIfNeeded( + Texture* texture, GLenum textarget) { + // This might be supported in the future. + if (textarget != GL_TEXTURE_2D) + return; + // Image is already in use if texture is attached to a framebuffer. + if (texture && !texture->IsAttachedToFramebuffer()) { + gfx::GLImage* image = texture->GetLevelImage(textarget, 0); + if (image) { + ScopedGLErrorSuppressor suppressor( + "GLES2DecoderImpl::DoWillUseTexImageIfNeeded", + GetErrorState()); + glBindTexture(textarget, texture->service_id()); + image->WillUseTexImage(); + RestoreCurrentTexture2DBindings(&state_); + } + } +} + +void GLES2DecoderImpl::DoDidUseTexImageIfNeeded( + Texture* texture, GLenum textarget) { + // This might be supported in the future. + if (textarget != GL_TEXTURE_2D) + return; + // Image is still in use if texture is attached to a framebuffer. + if (texture && !texture->IsAttachedToFramebuffer()) { + gfx::GLImage* image = texture->GetLevelImage(textarget, 0); + if (image) { + ScopedGLErrorSuppressor suppressor( + "GLES2DecoderImpl::DoDidUseTexImageIfNeeded", + GetErrorState()); + glBindTexture(textarget, texture->service_id()); + image->DidUseTexImage(); + RestoreCurrentTexture2DBindings(&state_); + } + } +} + bool GLES2DecoderImpl::PrepareTexturesForRender() { DCHECK(state_.current_program.get()); - bool have_unrenderable_textures = - texture_manager()->HaveUnrenderableTextures(); - if (!have_unrenderable_textures && !features().oes_egl_image_external) { + if (!texture_manager()->HaveUnrenderableTextures() && + !texture_manager()->HaveImages() && + !features().oes_egl_image_external) { return true; } @@ -5757,16 +6000,14 @@ bool GLES2DecoderImpl::PrepareTexturesForRender() { GLuint texture_unit_index = uniform_info->texture_units[jj]; if (texture_unit_index < state_.texture_units.size()) { TextureUnit& texture_unit = state_.texture_units[texture_unit_index]; - TextureRef* texture = + TextureRef* texture_ref = texture_unit.GetInfoForSamplerType(uniform_info->type).get(); - if (texture) - UpdateStreamTextureIfNeeded(texture->texture(), texture_unit_index); - if (have_unrenderable_textures && - (!texture || !texture_manager()->CanRender(texture))) { + GLenum textarget = GetBindTargetForSamplerType(uniform_info->type); + if (!texture_ref || !texture_manager()->CanRender(texture_ref)) { textures_set = true; glActiveTexture(GL_TEXTURE0 + texture_unit_index); glBindTexture( - GetBindTargetForSamplerType(uniform_info->type), + textarget, texture_manager()->black_texture_id(uniform_info->type)); LOCAL_RENDER_WARNING( std::string("texture bound to texture unit ") + @@ -5774,7 +6015,23 @@ bool GLES2DecoderImpl::PrepareTexturesForRender() { " is not renderable. It maybe non-power-of-2 and have" " incompatible texture filtering or is not" " 'texture complete'"); + continue; } + + Texture* texture = texture_ref->texture(); + if (textarget == GL_TEXTURE_2D) { + gfx::GLImage* image = texture->GetLevelImage(textarget, 0); + if (image && !texture->IsAttachedToFramebuffer()) { + ScopedGLErrorSuppressor suppressor( + "GLES2DecoderImpl::PrepareTexturesForRender", GetErrorState()); + textures_set = true; + glActiveTexture(GL_TEXTURE0 + texture_unit_index); + image->WillUseTexImage(); + continue; + } + } + + UpdateStreamTextureIfNeeded(texture, texture_unit_index); } // else: should this be an error? } @@ -5782,7 +6039,7 @@ bool GLES2DecoderImpl::PrepareTexturesForRender() { return !textures_set; } -void GLES2DecoderImpl::RestoreStateForNonRenderableTextures() { +void GLES2DecoderImpl::RestoreStateForTextures() { DCHECK(state_.current_program.get()); const Program::SamplerIndices& sampler_indices = state_.current_program->sampler_indices(); @@ -5795,9 +6052,7 @@ void GLES2DecoderImpl::RestoreStateForNonRenderableTextures() { if (texture_unit_index < state_.texture_units.size()) { TextureUnit& texture_unit = state_.texture_units[texture_unit_index]; TextureRef* texture_ref = - uniform_info->type == GL_SAMPLER_2D - ? texture_unit.bound_texture_2d.get() - : texture_unit.bound_texture_cube_map.get(); + texture_unit.GetInfoForSamplerType(uniform_info->type).get(); if (!texture_ref || !texture_manager()->CanRender(texture_ref)) { glActiveTexture(GL_TEXTURE0 + texture_unit_index); // Get the texture_ref info that was previously bound here. @@ -5806,6 +6061,20 @@ void GLES2DecoderImpl::RestoreStateForNonRenderableTextures() { : texture_unit.bound_texture_cube_map.get(); glBindTexture(texture_unit.bind_target, texture_ref ? texture_ref->service_id() : 0); + continue; + } + + Texture* texture = texture_ref->texture(); + if (texture_unit.bind_target == GL_TEXTURE_2D) { + gfx::GLImage* image = texture->GetLevelImage( + texture_unit.bind_target, 0); + if (image && !texture->IsAttachedToFramebuffer()) { + ScopedGLErrorSuppressor suppressor( + "GLES2DecoderImpl::RestoreStateForTextures", GetErrorState()); + glActiveTexture(GL_TEXTURE0 + texture_unit_index); + image->DidUseTexImage(); + continue; + } } } } @@ -6095,8 +6364,9 @@ error::Error GLES2DecoderImpl::DoDrawArrays( GLint first, GLsizei count, GLsizei primcount) { - if (ShouldDeferDraws()) - return error::kDeferCommandUntilLater; + error::Error error = WillAccessBoundFramebufferForDraw(); + if (error != error::kNoError) + return error; if (!validators_->draw_mode.IsValid(mode)) { LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, mode, "mode"); return error::kNoError; @@ -6148,7 +6418,7 @@ error::Error GLES2DecoderImpl::DoDrawArrays( } ProcessPendingQueries(); if (textures_set) { - RestoreStateForNonRenderableTextures(); + RestoreStateForTextures(); } if (simulated_fixed_attribs) { RestoreStateForSimulatedFixedAttribs(); @@ -6195,8 +6465,9 @@ error::Error GLES2DecoderImpl::DoDrawElements( GLenum type, int32 offset, GLsizei primcount) { - if (ShouldDeferDraws()) - return error::kDeferCommandUntilLater; + error::Error error = WillAccessBoundFramebufferForDraw(); + if (error != error::kNoError) + return error; if (!state_.vertex_attrib_manager->element_array_buffer()) { LOCAL_SET_GL_ERROR( GL_INVALID_OPERATION, function_name, "No element array buffer bound"); @@ -6282,7 +6553,7 @@ error::Error GLES2DecoderImpl::DoDrawElements( ProcessPendingQueries(); if (textures_set) { - RestoreStateForNonRenderableTextures(); + RestoreStateForTextures(); } if (simulated_fixed_attribs) { RestoreStateForSimulatedFixedAttribs(); @@ -6371,17 +6642,6 @@ error::Error GLES2DecoderImpl::HandleShaderSource( return ShaderSourceHelper(c.shader, data, data_size); } -error::Error GLES2DecoderImpl::HandleShaderSourceImmediate( - uint32 immediate_data_size, const cmds::ShaderSourceImmediate& c) { - uint32 data_size = c.data_size; - const char* data = GetImmediateDataAs<const char*>( - c, data_size, immediate_data_size); - if (!data) { - return error::kOutOfBounds; - } - return ShaderSourceHelper(c.shader, data, data_size); -} - error::Error GLES2DecoderImpl::HandleShaderSourceBucket( uint32 immediate_data_size, const cmds::ShaderSourceBucket& c) { Bucket* bucket = GetBucket(c.data_bucket_id); @@ -6405,7 +6665,11 @@ void GLES2DecoderImpl::DoCompileShader(GLuint client_id) { vertex_translator_.get() : fragment_translator_.get(); } - program_manager()->DoCompileShader(shader, translator, feature_info_.get()); + program_manager()->DoCompileShader( + shader, + translator, + feature_info_->feature_flags().angle_translated_shader_source ? + ProgramManager::kANGLE : ProgramManager::kGL); }; void GLES2DecoderImpl::DoGetShaderiv( @@ -6856,6 +7120,29 @@ error::Error GLES2DecoderImpl::HandleVertexAttribDivisorANGLE( return error::kNoError; } +template <typename pixel_data_type> +static void WriteAlphaData( + void *pixels, uint32 row_count, uint32 channel_count, + uint32 alpha_channel_index, uint32 unpadded_row_size, + uint32 padded_row_size, pixel_data_type alpha_value) { + DCHECK_GT(channel_count, 0U); + DCHECK_EQ(unpadded_row_size % sizeof(pixel_data_type), 0U); + uint32 unpadded_row_size_in_elements = + unpadded_row_size / sizeof(pixel_data_type); + DCHECK_EQ(padded_row_size % sizeof(pixel_data_type), 0U); + uint32 padded_row_size_in_elements = + padded_row_size / sizeof(pixel_data_type); + pixel_data_type* dst = + static_cast<pixel_data_type*>(pixels) + alpha_channel_index; + for (uint32 yy = 0; yy < row_count; ++yy) { + pixel_data_type* end = dst + unpadded_row_size_in_elements; + for (pixel_data_type* d = dst; d < end; d += channel_count) { + *d = alpha_value; + } + dst += padded_row_size_in_elements; + } +} + void GLES2DecoderImpl::FinishReadPixels( const cmds::ReadPixels& c, GLuint buffer) { @@ -6924,38 +7211,49 @@ void GLES2DecoderImpl::FinishReadPixels( &unpadded_row_size, &padded_row_size)) { return; } - // NOTE: Assumes the type is GL_UNSIGNED_BYTE which was true at the time - // of this implementation. - if (type != GL_UNSIGNED_BYTE) { - return; - } + + uint32 channel_count = 0; + uint32 alpha_channel = 0; switch (format) { case GL_RGBA: case GL_BGRA_EXT: - case GL_ALPHA: { - int offset = (format == GL_ALPHA) ? 0 : 3; - int step = (format == GL_ALPHA) ? 1 : 4; - uint8* dst = static_cast<uint8*>(pixels) + offset; - for (GLint yy = 0; yy < height; ++yy) { - uint8* end = dst + unpadded_row_size; - for (uint8* d = dst; d < end; d += step) { - *d = 255; - } - dst += padded_row_size; - } + channel_count = 4; + alpha_channel = 3; break; - } - default: + case GL_ALPHA: + channel_count = 1; + alpha_channel = 0; break; } + + if (channel_count > 0) { + switch (type) { + case GL_UNSIGNED_BYTE: + WriteAlphaData<uint8>( + pixels, height, channel_count, alpha_channel, unpadded_row_size, + padded_row_size, 0xFF); + break; + case GL_FLOAT: + WriteAlphaData<float>( + pixels, height, channel_count, alpha_channel, unpadded_row_size, + padded_row_size, 1.0f); + break; + case GL_HALF_FLOAT: + WriteAlphaData<uint16>( + pixels, height, channel_count, alpha_channel, unpadded_row_size, + padded_row_size, 0x3C00); + break; + } + } } } error::Error GLES2DecoderImpl::HandleReadPixels( uint32 immediate_data_size, const cmds::ReadPixels& c) { - if (ShouldDeferReads()) - return error::kDeferCommandUntilLater; + error::Error fbo_error = WillAccessBoundFramebufferForRead(); + if (fbo_error != error::kNoError) + return fbo_error; GLint x = c.x; GLint y = c.y; GLsizei width = c.width; @@ -6992,10 +7290,26 @@ error::Error GLES2DecoderImpl::HandleReadPixels( LOCAL_SET_GL_ERROR_INVALID_ENUM("glReadPixels", format, "format"); return error::kNoError; } - if (!validators_->pixel_type.IsValid(type)) { + if (!validators_->read_pixel_type.IsValid(type)) { LOCAL_SET_GL_ERROR_INVALID_ENUM("glReadPixels", type, "type"); return error::kNoError; } + if ((format != GL_RGBA && format != GL_BGRA_EXT && format != GL_RGB && + format != GL_ALPHA) || type != GL_UNSIGNED_BYTE) { + // format and type are acceptable enums but not guaranteed to be supported + // for this framebuffer. Have to ask gl if they are valid. + GLint preferred_format = 0; + DoGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &preferred_format); + GLint preferred_type = 0; + DoGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &preferred_type); + if (format != static_cast<GLenum>(preferred_format) || + type != static_cast<GLenum>(preferred_type)) { + LOCAL_SET_GL_ERROR( + GL_INVALID_OPERATION, "glReadPixels", "format and type incompatible " + "with the current read framebuffer"); + return error::kNoError; + } + } if (width == 0 || height == 0) { return error::kNoError; } @@ -7213,19 +7527,6 @@ error::Error GLES2DecoderImpl::HandleGetAttribLocation( c.program, c.location_shm_id, c.location_shm_offset, name_str); } -error::Error GLES2DecoderImpl::HandleGetAttribLocationImmediate( - uint32 immediate_data_size, const cmds::GetAttribLocationImmediate& c) { - uint32 name_size = c.data_size; - const char* name = GetImmediateDataAs<const char*>( - c, name_size, immediate_data_size); - if (!name) { - return error::kOutOfBounds; - } - String name_str(name, name_size); - return GetAttribLocationHelper( - c.program, c.location_shm_id, c.location_shm_offset, name_str); -} - error::Error GLES2DecoderImpl::HandleGetAttribLocationBucket( uint32 immediate_data_size, const cmds::GetAttribLocationBucket& c) { Bucket* bucket = GetBucket(c.name_bucket_id); @@ -7285,19 +7586,6 @@ error::Error GLES2DecoderImpl::HandleGetUniformLocation( c.program, c.location_shm_id, c.location_shm_offset, name_str); } -error::Error GLES2DecoderImpl::HandleGetUniformLocationImmediate( - uint32 immediate_data_size, const cmds::GetUniformLocationImmediate& c) { - uint32 name_size = c.data_size; - const char* name = GetImmediateDataAs<const char*>( - c, name_size, immediate_data_size); - if (!name) { - return error::kOutOfBounds; - } - String name_str(name, name_size); - return GetUniformLocationHelper( - c.program, c.location_shm_id, c.location_shm_offset, name_str); -} - error::Error GLES2DecoderImpl::HandleGetUniformLocationBucket( uint32 immediate_data_size, const cmds::GetUniformLocationBucket& c) { Bucket* bucket = GetBucket(c.name_bucket_id); @@ -7397,20 +7685,6 @@ error::Error GLES2DecoderImpl::HandleBufferData( return error::kNoError; } -error::Error GLES2DecoderImpl::HandleBufferDataImmediate( - uint32 immediate_data_size, const cmds::BufferDataImmediate& c) { - GLenum target = static_cast<GLenum>(c.target); - GLsizeiptr size = static_cast<GLsizeiptr>(c.size); - const void* data = GetImmediateDataAs<const void*>( - c, size, immediate_data_size); - if (!data) { - return error::kOutOfBounds; - } - GLenum usage = static_cast<GLenum>(c.usage); - buffer_manager()->ValidateAndDoBufferData(&state_, target, size, data, usage); - return error::kNoError; -} - void GLES2DecoderImpl::DoBufferSubData( GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid * data) { // Just delegate it. Some validation is actually done before this. @@ -7429,7 +7703,8 @@ bool GLES2DecoderImpl::ClearLevel( int height, bool is_texture_immutable) { uint32 channels = GLES2Util::GetChannelsForFormat(format); - if (IsAngle() && (channels & GLES2Util::kDepth) != 0) { + if (feature_info_->feature_flags().angle_depth_texture && + (channels & GLES2Util::kDepth) != 0) { // It's a depth format and ANGLE doesn't allow texImage2D or texSubImage2D // on depth formats. GLuint fb = 0; @@ -7762,24 +8037,6 @@ error::Error GLES2DecoderImpl::HandleCompressedTexImage2D( target, level, internal_format, width, height, border, image_size, data); } -error::Error GLES2DecoderImpl::HandleCompressedTexImage2DImmediate( - uint32 immediate_data_size, const cmds::CompressedTexImage2DImmediate& c) { - GLenum target = static_cast<GLenum>(c.target); - GLint level = static_cast<GLint>(c.level); - GLenum internal_format = static_cast<GLenum>(c.internalformat); - GLsizei width = static_cast<GLsizei>(c.width); - GLsizei height = static_cast<GLsizei>(c.height); - GLint border = static_cast<GLint>(c.border); - GLsizei image_size = static_cast<GLsizei>(c.imageSize); - const void* data = GetImmediateDataAs<const void*>( - c, image_size, immediate_data_size); - if (!data) { - return error::kOutOfBounds; - } - return DoCompressedTexImage2D( - target, level, internal_format, width, height, border, image_size, data); -} - error::Error GLES2DecoderImpl::HandleCompressedTexImage2DBucket( uint32 immediate_data_size, const cmds::CompressedTexImage2DBucket& c) { GLenum target = static_cast<GLenum>(c.target); @@ -7893,38 +8150,6 @@ error::Error GLES2DecoderImpl::HandleTexImage2D( return error::kNoError; } -error::Error GLES2DecoderImpl::HandleTexImage2DImmediate( - uint32 immediate_data_size, const cmds::TexImage2DImmediate& c) { - GLenum target = static_cast<GLenum>(c.target); - GLint level = static_cast<GLint>(c.level); - // TODO(kloveless): Change TexImage2DImmediate command to use unsigned - // integer for internalformat. - GLenum internal_format = static_cast<GLenum>(c.internalformat); - GLsizei width = static_cast<GLsizei>(c.width); - GLsizei height = static_cast<GLsizei>(c.height); - GLint border = static_cast<GLint>(c.border); - GLenum format = static_cast<GLenum>(c.format); - GLenum type = static_cast<GLenum>(c.type); - uint32 size; - if (!GLES2Util::ComputeImageDataSizes( - width, height, format, type, state_.unpack_alignment, &size, - NULL, NULL)) { - return error::kOutOfBounds; - } - const void* pixels = GetImmediateDataAs<const void*>( - c, size, immediate_data_size); - if (!pixels) { - return error::kOutOfBounds; - } - - TextureManager::DoTextImage2DArguments args = { - target, level, internal_format, width, height, border, format, type, - pixels, size}; - texture_manager()->ValidateAndDoTexImage2D( - &texture_state_, &state_, &framebuffer_state_, args); - return error::kNoError; -} - void GLES2DecoderImpl::DoCompressedTexSubImage2D( GLenum target, GLint level, @@ -8346,7 +8571,7 @@ error::Error GLES2DecoderImpl::DoTexSubImage2D( return error::kNoError; } - if (texture_state_.teximage2d_faster_than_texsubimage2d && + if (!texture_state_.texsubimage2d_faster_than_teximage2d && !texture->IsImmutable()) { ScopedTextureUploadTimer timer(&texture_state_); // NOTE: In OpenGL ES 2.0 border is always zero and format is always the @@ -8389,32 +8614,6 @@ error::Error GLES2DecoderImpl::HandleTexSubImage2D( target, level, xoffset, yoffset, width, height, format, type, pixels); } -error::Error GLES2DecoderImpl::HandleTexSubImage2DImmediate( - uint32 immediate_data_size, const cmds::TexSubImage2DImmediate& c) { - GLboolean internal = static_cast<GLboolean>(c.internal); - if (internal == GL_TRUE && texture_state_.tex_image_2d_failed) - return error::kNoError; - - GLenum target = static_cast<GLenum>(c.target); - GLint level = static_cast<GLint>(c.level); - GLint xoffset = static_cast<GLint>(c.xoffset); - GLint yoffset = static_cast<GLint>(c.yoffset); - GLsizei width = static_cast<GLsizei>(c.width); - GLsizei height = static_cast<GLsizei>(c.height); - GLenum format = static_cast<GLenum>(c.format); - GLenum type = static_cast<GLenum>(c.type); - uint32 data_size; - if (!GLES2Util::ComputeImageDataSizes( - width, height, format, type, state_.unpack_alignment, &data_size, - NULL, NULL)) { - return error::kOutOfBounds; - } - const void* pixels = GetImmediateDataAs<const void*>( - c, data_size, immediate_data_size); - return DoTexSubImage2D( - target, level, xoffset, yoffset, width, height, format, type, pixels); -} - error::Error GLES2DecoderImpl::HandleGetVertexAttribPointerv( uint32 immediate_data_size, const cmds::GetVertexAttribPointerv& c) { GLuint index = static_cast<GLuint>(c.index); @@ -8809,7 +9008,7 @@ void GLES2DecoderImpl::DoSwapBuffers() { if (offscreen_size_.width() == 0 || offscreen_size_.height() == 0) return; ScopedGLErrorSuppressor suppressor( - "GLES2DecoderImpl::DoSwapBuffers", this); + "GLES2DecoderImpl::DoSwapBuffers", GetErrorState()); if (IsOffscreenBufferMultisampled()) { // For multisampled buffers, resolve the frame buffer. @@ -8837,7 +9036,7 @@ void GLES2DecoderImpl::DoSwapBuffers() { // Ensure the side effects of the copy are visible to the parent // context. There is no need to do this for ANGLE because it uses a // single D3D device for all contexts. - if (!IsAngle()) + if (!feature_info_->feature_flags().is_angle) glFlush(); } } else { @@ -9128,6 +9327,18 @@ error::Error GLES2DecoderImpl::HandleWaitSyncPointCHROMIUM( error::kNoError : error::kDeferCommandUntilLater; } +error::Error GLES2DecoderImpl::HandleDiscardBackbufferCHROMIUM( + uint32 immediate_data_size, const cmds::DiscardBackbufferCHROMIUM& c) { + if (surface_->DeferDraws()) + return error::kDeferCommandUntilLater; + if (!surface_->SetBackbufferAllocation(false)) + return error::kLostContext; + backbuffer_needs_clear_bits_ |= GL_COLOR_BUFFER_BIT; + backbuffer_needs_clear_bits_ |= GL_DEPTH_BUFFER_BIT; + backbuffer_needs_clear_bits_ |= GL_STENCIL_BUFFER_BIT; + return error::kNoError; +} + bool GLES2DecoderImpl::GenQueriesEXTHelper( GLsizei n, const GLuint* client_ids) { for (GLsizei ii = 0; ii < n; ++ii) { @@ -9649,34 +9860,17 @@ void GLES2DecoderImpl::DoCopyTextureCHROMIUM( if (dest_texture->target() != GL_TEXTURE_2D || (source_texture->target() != GL_TEXTURE_2D && source_texture->target() != GL_TEXTURE_EXTERNAL_OES)) { - LOCAL_SET_GL_ERROR( - GL_INVALID_VALUE, - "glCopyTextureCHROMIUM", "invalid texture target binding"); + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, + "glCopyTextureCHROMIUM", + "invalid texture target binding"); return; } int source_width, source_height, dest_width, dest_height; - if (source_texture->target() == GL_TEXTURE_2D) { - if (!source_texture->GetLevelSize(GL_TEXTURE_2D, 0, &source_width, - &source_height)) { - LOCAL_SET_GL_ERROR( - GL_INVALID_VALUE, - "glCopyTextureChromium", "source texture has no level 0"); - return; - } - - // Check that this type of texture is allowed. - if (!texture_manager()->ValidForTarget(GL_TEXTURE_2D, level, source_width, - source_height, 1)) { - LOCAL_SET_GL_ERROR( - GL_INVALID_VALUE, - "glCopyTextureCHROMIUM", "Bad dimensions"); - return; - } - } - - if (source_texture->target() == GL_TEXTURE_EXTERNAL_OES) { + if (source_texture->IsStreamTexture()) { + DCHECK_EQ(source_texture->target(), + static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES)); DCHECK(stream_texture_manager()); StreamTexture* stream_tex = stream_texture_manager()->LookupStreamTexture( @@ -9696,6 +9890,30 @@ void GLES2DecoderImpl::DoCopyTextureCHROMIUM( "glCopyTextureChromium", "invalid streamtexture size"); return; } + } else { + if (!source_texture->GetLevelSize( + source_texture->target(), 0, &source_width, &source_height)) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, + "glCopyTextureChromium", + "source texture has no level 0"); + return; + } + + // Check that this type of texture is allowed. + if (!texture_manager()->ValidForTarget( + source_texture->target(), level, source_width, source_height, 1)) { + LOCAL_SET_GL_ERROR( + GL_INVALID_VALUE, "glCopyTextureCHROMIUM", "Bad dimensions"); + return; + } + } + + // Clear the source texture if necessary. + if (!texture_manager()->ClearTextureLevel( + this, source_texture_ref, source_texture->target(), 0)) { + LOCAL_SET_GL_ERROR( + GL_OUT_OF_MEMORY, "glCopyTextureCHROMIUM", "dimensions too big"); + return; } // Defer initializing the CopyTextureCHROMIUMResourceManager until it is @@ -9732,7 +9950,7 @@ void GLES2DecoderImpl::DoCopyTextureCHROMIUM( 0, internal_format, dest_type, NULL); GLenum error = LOCAL_PEEK_GL_ERROR("glCopyTextureCHROMIUM"); if (error != GL_NO_ERROR) { - RestoreCurrentTexture2DBindings(); + RestoreCurrentTexture2DBindings(&state_); return; } @@ -9744,6 +9962,8 @@ void GLES2DecoderImpl::DoCopyTextureCHROMIUM( dest_texture_ref, GL_TEXTURE_2D, level, true); } + DoWillUseTexImageIfNeeded(source_texture, source_texture->target()); + // GL_TEXTURE_EXTERNAL_OES texture requires apply a transform matrix // before presenting. if (source_texture->target() == GL_TEXTURE_EXTERNAL_OES) { @@ -9776,6 +9996,8 @@ void GLES2DecoderImpl::DoCopyTextureCHROMIUM( unpack_premultiply_alpha_, unpack_unpremultiply_alpha_); } + + DoDidUseTexImageIfNeeded(source_texture, source_texture->target()); } static GLenum ExtractTypeFromStorageFormat(GLenum internalformat) { @@ -9831,7 +10053,7 @@ void GLES2DecoderImpl::DoTexStorage2DEXT( GLsizei height) { TRACE_EVENT0("gpu", "GLES2DecoderImpl::DoTexStorage2DEXT"); if (!texture_manager()->ValidForTarget(target, 0, width, height, 1) || - TextureManager::ComputeMipMapCount(width, height, 1) < levels) { + TextureManager::ComputeMipMapCount(target, width, height, 1) < levels) { LOCAL_SET_GL_ERROR( GL_INVALID_VALUE, "glTexStorage2DEXT", "dimensions out of range"); return; @@ -9901,15 +10123,7 @@ void GLES2DecoderImpl::DoTexStorage2DEXT( error::Error GLES2DecoderImpl::HandleGenMailboxCHROMIUM( uint32 immediate_data_size, const cmds::GenMailboxCHROMIUM& c) { - MailboxName name; - mailbox_manager()->GenerateMailboxName(&name); - uint32 bucket_id = static_cast<uint32>(c.bucket_id); - Bucket* bucket = CreateBucket(bucket_id); - - bucket->SetSize(GL_MAILBOX_SIZE_CHROMIUM); - bucket->SetData(&name, 0, GL_MAILBOX_SIZE_CHROMIUM); - - return error::kNoError; + return error::kUnknownCommand; } void GLES2DecoderImpl::DoProduceTextureCHROMIUM(GLenum target, @@ -10034,13 +10248,6 @@ void GLES2DecoderImpl::DoPopGroupMarkerEXT(void) { void GLES2DecoderImpl::DoBindTexImage2DCHROMIUM( GLenum target, GLint image_id) { TRACE_EVENT0("gpu", "GLES2DecoderImpl::DoBindTexImage2DCHROMIUM"); - if (target != GL_TEXTURE_2D) { - // This might be supported in the future. - LOCAL_SET_GL_ERROR( - GL_INVALID_OPERATION, - "glBindTexImage2DCHROMIUM", "requires TEXTURE_2D target"); - return; - } // Default target might be conceptually valid, but disallow it to avoid // accidents. @@ -10063,8 +10270,8 @@ void GLES2DecoderImpl::DoBindTexImage2DCHROMIUM( { ScopedGLErrorSuppressor suppressor( - "GLES2DecoderImpl::DoBindTexImage2DCHROMIUM", this); - if (!gl_image->BindTexImage()) { + "GLES2DecoderImpl::DoBindTexImage2DCHROMIUM", GetErrorState()); + if (!gl_image->BindTexImage(target)) { LOCAL_SET_GL_ERROR( GL_INVALID_OPERATION, "glBindTexImage2DCHROMIUM", "fail to bind image with the given ID"); @@ -10082,13 +10289,6 @@ void GLES2DecoderImpl::DoBindTexImage2DCHROMIUM( void GLES2DecoderImpl::DoReleaseTexImage2DCHROMIUM( GLenum target, GLint image_id) { TRACE_EVENT0("gpu", "GLES2DecoderImpl::DoReleaseTexImage2DCHROMIUM"); - if (target != GL_TEXTURE_2D) { - // This might be supported in the future. - LOCAL_SET_GL_ERROR( - GL_INVALID_OPERATION, - "glReleaseTexImage2DCHROMIUM", "requires TEXTURE_2D target"); - return; - } // Default target might be conceptually valid, but disallow it to avoid // accidents. @@ -10115,8 +10315,8 @@ void GLES2DecoderImpl::DoReleaseTexImage2DCHROMIUM( { ScopedGLErrorSuppressor suppressor( - "GLES2DecoderImpl::DoReleaseTexImage2DCHROMIUM", this); - gl_image->ReleaseTexImage(); + "GLES2DecoderImpl::DoReleaseTexImage2DCHROMIUM", GetErrorState()); + gl_image->ReleaseTexImage(target); } texture_manager()->SetLevelInfo( @@ -10449,6 +10649,12 @@ error::Error GLES2DecoderImpl::HandleWaitAsyncTexImage2DCHROMIUM( return error::kNoError; } +void GLES2DecoderImpl::OnTextureRefDetachedFromFramebuffer( + TextureRef* texture_ref) { + Texture* texture = texture_ref->texture(); + DoDidUseTexImageIfNeeded(texture, texture->target()); +} + // Include the auto-generated part of this file. We split this because it means // we can easily edit the non-auto generated parts right here in this file // instead of having to edit some template or the code generator. |