| 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 d6f5702b6346f09821e508724db4de22a34705ba..0e48e509334dd66706107f27898a11b4c8bb200c 100644
|
| --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
|
| +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
|
| @@ -59,6 +59,7 @@
|
| #include "gpu/command_buffer/service/vertex_array_manager.h"
|
| #include "gpu/command_buffer/service/vertex_attrib_manager.h"
|
| #include "ui/gl/gl_bindings.h"
|
| +#include "ui/gl/gl_fence.h"
|
| #include "ui/gl/gl_image.h"
|
| #include "ui/gl/gl_implementation.h"
|
| #include "ui/gl/gl_surface.h"
|
| @@ -476,6 +477,17 @@ class BackFramebuffer {
|
| DISALLOW_COPY_AND_ASSIGN(BackFramebuffer);
|
| };
|
|
|
| +struct FenceCallback {
|
| + explicit FenceCallback(base::Closure callback_)
|
| + : callback(callback_),
|
| + fence(gfx::GLFence::Create()) {
|
| + DCHECK(fence);
|
| + }
|
| + base::Closure callback;
|
| + scoped_ptr<gfx::GLFence> fence;
|
| +};
|
| +
|
| +
|
| // } // anonymous namespace.
|
|
|
| bool GLES2Decoder::GetServiceTextureId(uint32 client_texture_id,
|
| @@ -586,6 +598,8 @@ class GLES2DecoderImpl : public GLES2Decoder {
|
| virtual bool HasMoreIdleWork() OVERRIDE;
|
| virtual void PerformIdleWork() OVERRIDE;
|
|
|
| + virtual void WaitForReadPixels(base::Closure callback) OVERRIDE;
|
| +
|
| virtual void SetResizeCallback(
|
| const base::Callback<void(gfx::Size, float)>& callback) OVERRIDE;
|
|
|
| @@ -1554,6 +1568,9 @@ class GLES2DecoderImpl : public GLES2Decoder {
|
| surface_->DeferDraws();
|
| }
|
|
|
| + void ProcessPendingReadPixels();
|
| + void FinishReadPixels(const cmds::ReadPixels& c, GLuint buffer);
|
| +
|
| void ForceCompileShaderIfPending(Shader* shader);
|
|
|
| // Generate a member function prototype for each command in an automated and
|
| @@ -1722,6 +1739,8 @@ class GLES2DecoderImpl : public GLES2Decoder {
|
|
|
| scoped_ptr<GPUTracer> gpu_tracer_;
|
|
|
| + std::queue<linked_ptr<FenceCallback> > pending_fences_;
|
| +
|
| DISALLOW_COPY_AND_ASSIGN(GLES2DecoderImpl);
|
| };
|
|
|
| @@ -2496,6 +2515,7 @@ bool GLES2DecoderImpl::Initialize(
|
| AsyncPixelTransferManager::Create(context.get()));
|
| async_pixel_transfer_manager_->Initialize(texture_manager());
|
|
|
| +
|
| return true;
|
| }
|
|
|
| @@ -3537,6 +3557,7 @@ bool GLES2DecoderImpl::CreateShaderHelper(GLenum type, GLuint client_id) {
|
|
|
| void GLES2DecoderImpl::DoFinish() {
|
| glFinish();
|
| + ProcessPendingReadPixels();
|
| ProcessPendingQueries();
|
| }
|
|
|
| @@ -6699,6 +6720,94 @@ error::Error GLES2DecoderImpl::HandleVertexAttribDivisorANGLE(
|
| return error::kNoError;
|
| }
|
|
|
| +void GLES2DecoderImpl::FinishReadPixels(
|
| + const cmds::ReadPixels& c,
|
| + GLuint buffer) {
|
| + TRACE_EVENT0("gpu", "GLES2DecoderImpl::FinishReadPixels");
|
| + GLsizei width = c.width;
|
| + GLsizei height = c.height;
|
| + GLenum format = c.format;
|
| + GLenum type = c.type;
|
| + typedef cmds::ReadPixels::Result Result;
|
| + uint32 pixels_size;
|
| + GLES2Util::ComputeImageDataSizes(
|
| + width, height, format, type, state_.pack_alignment, &pixels_size,
|
| + NULL, NULL);
|
| + void* pixels = GetSharedMemoryAs<void*>(
|
| + c.pixels_shm_id, c.pixels_shm_offset, pixels_size);
|
| + if (!pixels) {
|
| + if (buffer != 0) {
|
| + glDeleteBuffersARB(1, &buffer);
|
| + return;
|
| + }
|
| + }
|
| +
|
| + if (buffer != 0) {
|
| + glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, buffer);
|
| + void* data = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
|
| + memcpy(pixels, data, pixels_size);
|
| + // GL_PIXEL_PACK_BUFFER_ARB is currently unused, so we don't
|
| + // have to restore the state.
|
| + glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);
|
| + glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
|
| + glDeleteBuffersARB(1, &buffer);
|
| + }
|
| + Result* result = NULL;
|
| + if (c.result_shm_id != 0) {
|
| + result = GetSharedMemoryAs<Result*>(
|
| + c.result_shm_id, c.result_shm_offset, sizeof(*result));
|
| + if (!result) {
|
| + // No way to mark failure.
|
| + return;
|
| + }
|
| + }
|
| +
|
| + if (result != NULL) {
|
| + *result = true;
|
| + }
|
| +
|
| + GLenum read_format = GetBoundReadFrameBufferInternalFormat();
|
| + uint32 channels_exist = GLES2Util::GetChannelsForFormat(read_format);
|
| + if ((channels_exist & 0x0008) == 0 &&
|
| + workarounds().clear_alpha_in_readpixels) {
|
| + // Set the alpha to 255 because some drivers are buggy in this regard.
|
| + uint32 temp_size;
|
| +
|
| + uint32 unpadded_row_size;
|
| + uint32 padded_row_size;
|
| + if (!GLES2Util::ComputeImageDataSizes(
|
| + width, 2, format, type, state_.pack_alignment, &temp_size,
|
| + &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;
|
| + }
|
| + 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;
|
| + }
|
| + break;
|
| + }
|
| + default:
|
| + break;
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| error::Error GLES2DecoderImpl::HandleReadPixels(
|
| uint32 immediate_data_size, const cmds::ReadPixels& c) {
|
| if (ShouldDeferReads())
|
| @@ -6709,6 +6818,7 @@ error::Error GLES2DecoderImpl::HandleReadPixels(
|
| GLsizei height = c.height;
|
| GLenum format = c.format;
|
| GLenum type = c.type;
|
| + GLboolean async = c.async;
|
| if (width < 0 || height < 0) {
|
| LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glReadPixels", "dimensions < 0");
|
| return error::kNoError;
|
| @@ -6808,6 +6918,23 @@ error::Error GLES2DecoderImpl::HandleReadPixels(
|
| dst += padded_row_size;
|
| }
|
| } else {
|
| + if (async && features().use_async_readpixels) {
|
| + GLuint buffer;
|
| + glGenBuffersARB(1, &buffer);
|
| + glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, buffer);
|
| + glBufferData(GL_PIXEL_PACK_BUFFER_ARB, pixels_size, NULL, GL_STREAM_READ);
|
| + GLenum error = glGetError();
|
| + if (error == GL_NO_ERROR) {
|
| + glReadPixels(x, y, width, height, format, type, 0);
|
| + WaitForReadPixels(base::Bind(
|
| + &GLES2DecoderImpl::FinishReadPixels,
|
| + base::internal::SupportsWeakPtrBase::StaticAsWeakPtr
|
| + <GLES2DecoderImpl>(this),
|
| + c, buffer));
|
| + glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
|
| + return error::kNoError;
|
| + }
|
| + }
|
| glReadPixels(x, y, width, height, format, type, pixels);
|
| }
|
| GLenum error = LOCAL_PEEK_GL_ERROR("glReadPixels");
|
| @@ -6815,51 +6942,7 @@ error::Error GLES2DecoderImpl::HandleReadPixels(
|
| if (result != NULL) {
|
| *result = true;
|
| }
|
| -
|
| - GLenum read_format = GetBoundReadFrameBufferInternalFormat();
|
| - uint32 channels_exist = GLES2Util::GetChannelsForFormat(read_format);
|
| - if ((channels_exist & 0x0008) == 0 &&
|
| - workarounds().clear_alpha_in_readpixels) {
|
| - // Set the alpha to 255 because some drivers are buggy in this regard.
|
| - uint32 temp_size;
|
| -
|
| - uint32 unpadded_row_size;
|
| - uint32 padded_row_size;
|
| - if (!GLES2Util::ComputeImageDataSizes(
|
| - width, 2, format, type, state_.pack_alignment, &temp_size,
|
| - &unpadded_row_size, &padded_row_size)) {
|
| - LOCAL_SET_GL_ERROR(
|
| - GL_INVALID_VALUE, "glReadPixels", "dimensions out of range");
|
| - return error::kNoError;
|
| - }
|
| - // NOTE: Assumes the type is GL_UNSIGNED_BYTE which was true at the time
|
| - // of this implementation.
|
| - if (type != GL_UNSIGNED_BYTE) {
|
| - LOCAL_SET_GL_ERROR(
|
| - GL_INVALID_OPERATION, "glReadPixels",
|
| - "unsupported readPixel format");
|
| - return error::kNoError;
|
| - }
|
| - 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;
|
| - }
|
| - break;
|
| - }
|
| - default:
|
| - break;
|
| - }
|
| - }
|
| + FinishReadPixels(c, 0);
|
| }
|
|
|
| return error::kNoError;
|
| @@ -9089,11 +9172,30 @@ bool GLES2DecoderImpl::ProcessPendingQueries() {
|
| return query_manager_->HavePendingQueries();
|
| }
|
|
|
| +void GLES2DecoderImpl::WaitForReadPixels(base::Closure callback) {
|
| + if (features().use_async_readpixels) {
|
| + pending_fences_.push(linked_ptr<FenceCallback>(
|
| + new FenceCallback(callback)));
|
| + } else {
|
| + callback.Run();
|
| + }
|
| +}
|
| +
|
| +void GLES2DecoderImpl::ProcessPendingReadPixels() {
|
| + while (!pending_fences_.empty() &&
|
| + pending_fences_.front()->fence->HasCompleted()) {
|
| + pending_fences_.front()->callback.Run();
|
| + pending_fences_.pop();
|
| + }
|
| +}
|
| +
|
| bool GLES2DecoderImpl::HasMoreIdleWork() {
|
| - return async_pixel_transfer_manager_->NeedsProcessMorePendingTransfers();
|
| + return !pending_fences_.empty() ||
|
| + async_pixel_transfer_manager_->NeedsProcessMorePendingTransfers();
|
| }
|
|
|
| void GLES2DecoderImpl::PerformIdleWork() {
|
| + ProcessPendingReadPixels();
|
| if (!async_pixel_transfer_manager_->NeedsProcessMorePendingTransfers())
|
| return;
|
| async_pixel_transfer_manager_->ProcessMorePendingTransfers();
|
|
|