summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cc/output/gl_renderer.cc21
-rw-r--r--cc/output/gl_renderer.h1
-rw-r--r--cc/test/test_web_graphics_context_3d.cc6
-rw-r--r--cc/test/test_web_graphics_context_3d.h2
-rw-r--r--content/common/gpu/client/gl_helper.cc80
-rw-r--r--gpu/GLES2/gl2extchromium.h3
-rwxr-xr-xgpu/command_buffer/build_gles2_cmd_buffer.py4
-rw-r--r--gpu/command_buffer/client/gles2_cmd_helper_autogen.h4
-rw-r--r--gpu/command_buffer/client/gles2_implementation.cc6
-rw-r--r--gpu/command_buffer/client/gles2_implementation_unittest.cc7
-rw-r--r--gpu/command_buffer/client/query_tracker.cc7
-rw-r--r--gpu/command_buffer/common/gles2_cmd_format_autogen.h14
-rw-r--r--gpu/command_buffer/common/gles2_cmd_format_test_autogen.h4
-rw-r--r--gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h4
-rw-r--r--gpu/command_buffer/service/feature_info.cc13
-rw-r--r--gpu/command_buffer/service/feature_info.h1
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc208
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.h1
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_mock.h2
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc43
-rw-r--r--gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h1
-rw-r--r--gpu/command_buffer/service/query_manager.cc60
-rw-r--r--gpu/command_buffer/tests/gl_readback_unittests.cc60
-rw-r--r--gpu/config/gpu_driver_bug_list_json.cc4
-rw-r--r--ui/gl/gl_bindings.h1
25 files changed, 404 insertions, 153 deletions
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index c801553..3cb6c2b 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -2302,6 +2302,14 @@ void GLRenderer::DoGetFramebufferPixels(
NULL,
GL_STREAM_READ));
+ WebKit::WebGLId query = 0;
+ if (is_async) {
+ query = context_->createQueryEXT();
+ GLC(context_, context_->beginQueryEXT(
+ GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM,
+ query));
+ }
+
GLC(context_,
context_->readPixels(window_rect.x(),
window_rect.y(),
@@ -2327,6 +2335,7 @@ void GLRenderer::DoGetFramebufferPixels(
base::Unretained(this),
cleanup_callback,
buffer,
+ query,
dest_pixels,
window_rect.size());
// Save the finished_callback so it can be cancelled.
@@ -2337,10 +2346,11 @@ void GLRenderer::DoGetFramebufferPixels(
pending_async_read_pixels_.front()->buffer = buffer;
if (is_async) {
- unsigned sync_point = context_->insertSyncPoint();
- SyncPointHelper::SignalSyncPoint(
+ GLC(context_, context_->endQueryEXT(
+ GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM));
+ SyncPointHelper::SignalQuery(
context_,
- sync_point,
+ query,
finished_callback);
} else {
resource_provider_->Finish();
@@ -2353,10 +2363,15 @@ void GLRenderer::DoGetFramebufferPixels(
void GLRenderer::FinishedReadback(
const AsyncGetFramebufferPixelsCleanupCallback& cleanup_callback,
unsigned source_buffer,
+ unsigned query,
uint8* dest_pixels,
gfx::Size size) {
DCHECK(!pending_async_read_pixels_.empty());
+ if (query != 0) {
+ GLC(context_, context_->deleteQueryEXT(query));
+ }
+
PendingAsyncReadPixels* current_read = pending_async_read_pixels_.back();
// Make sure we service the readbacks in order.
DCHECK_EQ(source_buffer, current_read->buffer);
diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h
index 6638993..3e06537 100644
--- a/cc/output/gl_renderer.h
+++ b/cc/output/gl_renderer.h
@@ -201,6 +201,7 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
void FinishedReadback(
const AsyncGetFramebufferPixelsCleanupCallback& cleanup_callback,
unsigned source_buffer,
+ unsigned query,
uint8_t* dest_pixels,
gfx::Size size);
void PassOnSkBitmap(scoped_ptr<SkBitmap> bitmap,
diff --git a/cc/test/test_web_graphics_context_3d.cc b/cc/test/test_web_graphics_context_3d.cc
index 9e5488b..44d43f9 100644
--- a/cc/test/test_web_graphics_context_3d.cc
+++ b/cc/test/test_web_graphics_context_3d.cc
@@ -415,6 +415,12 @@ void TestWebGraphicsContext3D::signalSyncPoint(
sync_point_callbacks_.push_back(callback);
}
+void TestWebGraphicsContext3D::signalQuery(
+ WebKit::WebGLId query,
+ WebGraphicsSyncPointCallback* callback) {
+ sync_point_callbacks_.push_back(callback);
+}
+
void TestWebGraphicsContext3D::setSwapBuffersCompleteCallbackCHROMIUM(
WebGraphicsSwapBuffersCompleteCallbackCHROMIUM* callback) {
if (support_swapbuffers_complete_callback_)
diff --git a/cc/test/test_web_graphics_context_3d.h b/cc/test/test_web_graphics_context_3d.h
index 41296b2..b182fe6 100644
--- a/cc/test/test_web_graphics_context_3d.h
+++ b/cc/test/test_web_graphics_context_3d.h
@@ -114,6 +114,8 @@ class TestWebGraphicsContext3D : public FakeWebGraphicsContext3D {
// Takes ownership of the |callback|.
virtual void signalSyncPoint(unsigned sync_point,
WebGraphicsSyncPointCallback* callback);
+ virtual void signalQuery(WebKit::WebGLId query,
+ WebGraphicsSyncPointCallback* callback);
virtual void setSwapBuffersCompleteCallbackCHROMIUM(
WebGraphicsSwapBuffersCompleteCallbackCHROMIUM* callback);
diff --git a/content/common/gpu/client/gl_helper.cc b/content/common/gpu/client/gl_helper.cc
index 22d5f03..e8afdd1 100644
--- a/content/common/gpu/client/gl_helper.cc
+++ b/content/common/gpu/client/gl_helper.cc
@@ -195,20 +195,24 @@ class GLHelper::CopyTextureToImpl :
int32 row_stride_bytes_,
unsigned char* pixels_,
const base::Callback<void(bool)>& callback_)
- : size(size_),
+ : done(false),
+ size(size_),
bytes_per_row(bytes_per_row_),
row_stride_bytes(row_stride_bytes_),
pixels(pixels_),
callback(callback_),
- buffer(0) {
+ buffer(0),
+ query(0) {
}
+ bool done;
gfx::Size size;
int bytes_per_row;
int row_stride_bytes;
unsigned char* pixels;
base::Callback<void(bool)> callback;
GLuint buffer;
+ WebKit::WebGLId query;
};
// A readback pipeline that also converts the data to YUV before
@@ -301,7 +305,7 @@ class GLHelper::CopyTextureToImpl :
GLHelper::ScalerQuality quality);
static void nullcallback(bool success) {}
- void ReadbackDone(Request* request);
+ void ReadbackDone(Request *request);
void FinishRequest(Request* request, bool result);
void CancelRequests();
@@ -389,12 +393,16 @@ void GLHelper::CopyTextureToImpl::ReadbackAsync(
NULL,
GL_STREAM_READ);
+ request->query = context_->createQueryEXT();
+ context_->beginQueryEXT(GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM,
+ request->query);
context_->readPixels(0, 0, dst_size.width(), dst_size.height(),
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ context_->endQueryEXT(GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM);
context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
- cc::SyncPointHelper::SignalSyncPoint(
+ cc::SyncPointHelper::SignalQuery(
context_,
- context_->insertSyncPoint(),
+ request->query,
base::Bind(&CopyTextureToImpl::ReadbackDone, AsWeakPtr(), request));
}
@@ -472,45 +480,59 @@ WebKit::WebGLId GLHelper::CopyTextureToImpl::CopyAndScaleTexture(
quality);
}
-void GLHelper::CopyTextureToImpl::ReadbackDone(Request* request) {
+void GLHelper::CopyTextureToImpl::ReadbackDone(Request* finished_request) {
TRACE_EVENT0("mirror",
"GLHelper::CopyTextureToImpl::CheckReadbackFramebufferComplete");
- DCHECK(request == request_queue_.front());
+ finished_request->done = true;
- bool result = false;
- if (request->buffer != 0) {
- context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
- request->buffer);
- unsigned char* data = static_cast<unsigned char *>(
- context_->mapBufferCHROMIUM(
- GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
- if (data) {
- result = true;
- if (request->bytes_per_row == request->size.width() * 4 &&
- request->bytes_per_row == request->row_stride_bytes) {
- memcpy(request->pixels, data, request->size.GetArea() * 4);
- } else {
- unsigned char* out = request->pixels;
- for (int y = 0; y < request->size.height(); y++) {
- memcpy(out, data, request->bytes_per_row);
- out += request->row_stride_bytes;
- data += request->size.width() * 4;
+ // We process transfer requests in the order they were received, regardless
+ // of the order we get the callbacks in.
+ while (!request_queue_.empty()) {
+ Request* request = request_queue_.front();
+ if (!request->done) {
+ break;
+ }
+
+ bool result = false;
+ if (request->buffer != 0) {
+ context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
+ request->buffer);
+ unsigned char* data = static_cast<unsigned char *>(
+ context_->mapBufferCHROMIUM(
+ GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
+ if (data) {
+ result = true;
+ if (request->bytes_per_row == request->size.width() * 4 &&
+ request->bytes_per_row == request->row_stride_bytes) {
+ memcpy(request->pixels, data, request->size.GetArea() * 4);
+ } else {
+ unsigned char* out = request->pixels;
+ for (int y = 0; y < request->size.height(); y++) {
+ memcpy(out, data, request->bytes_per_row);
+ out += request->row_stride_bytes;
+ data += request->size.width() * 4;
+ }
}
+ context_->unmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
}
- context_->unmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
+ context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
}
- context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
- }
- FinishRequest(request, result);
+ FinishRequest(request, result);
+ }
}
void GLHelper::CopyTextureToImpl::FinishRequest(Request* request,
bool result) {
+ TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::FinishRequest");
DCHECK(request_queue_.front() == request);
request_queue_.pop();
request->callback.Run(result);
ScopedFlush flush(context_);
+ if (request->query != 0) {
+ context_->deleteQueryEXT(request->query);
+ request->query = 0;
+ }
if (request->buffer != 0) {
context_->deleteBuffer(request->buffer);
request->buffer = 0;
diff --git a/gpu/GLES2/gl2extchromium.h b/gpu/GLES2/gl2extchromium.h
index 2568074..433242c 100644
--- a/gpu/GLES2/gl2extchromium.h
+++ b/gpu/GLES2/gl2extchromium.h
@@ -339,6 +339,9 @@ typedef void (GL_APIENTRYP PFNGLBINDUNIFORMLOCATIONCHROMIUMPROC) (
#ifndef GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM
#define GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM 0x84F5
#endif
+#ifndef GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM
+#define GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM 0x84F6
+#endif
#endif /* GL_CHROMIUM_async_pixel_transfers */
/* GL_CHROMIUM_copy_texture */
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index 460ae72..6555da2 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -826,6 +826,7 @@ _ENUM_LISTS = {
'GL_COMMANDS_ISSUED_CHROMIUM',
'GL_LATENCY_QUERY_CHROMIUM',
'GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM',
+ 'GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM',
],
},
'RenderBufferParameter': {
@@ -1908,7 +1909,8 @@ _FUNCTION_INFO = {
'GLint x, GLint y, GLsizei width, GLsizei height, '
'GLenumReadPixelFormat format, GLenumReadPixelType type, '
'uint32 pixels_shm_id, uint32 pixels_shm_offset, '
- 'uint32 result_shm_id, uint32 result_shm_offset',
+ 'uint32 result_shm_id, uint32 result_shm_offset, '
+ 'GLboolean async',
'result': ['uint32'],
'defer_reads': True,
},
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
index 742c97e..8d2fd7d 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -923,12 +923,12 @@
void ReadPixels(
GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
GLenum type, uint32 pixels_shm_id, uint32 pixels_shm_offset,
- uint32 result_shm_id, uint32 result_shm_offset) {
+ uint32 result_shm_id, uint32 result_shm_offset, GLboolean async) {
gles2::cmds::ReadPixels* c = GetCmdSpace<gles2::cmds::ReadPixels>();
if (c) {
c->Init(
x, y, width, height, format, type, pixels_shm_id, pixels_shm_offset,
- result_shm_id, result_shm_offset);
+ result_shm_id, result_shm_offset, async);
}
}
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 1bc3f0b3..e13a1ec 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -2236,8 +2236,7 @@ void GLES2Implementation::ReadPixels(
if (buffer && buffer->shm_id() != -1) {
helper_->ReadPixels(xoffset, yoffset, width, height, format, type,
buffer->shm_id(), buffer->shm_offset(),
- 0, 0);
- buffer->set_transfer_ready_token(helper_->InsertToken());
+ 0, 0, true);
CheckGLError();
}
return;
@@ -2269,7 +2268,8 @@ void GLES2Implementation::ReadPixels(
helper_->ReadPixels(
xoffset, yoffset, width, num_rows, format, type,
buffer.shm_id(), buffer.offset(),
- GetResultShmId(), GetResultShmOffset());
+ GetResultShmId(), GetResultShmOffset(),
+ false);
WaitForCmd();
if (*result != 0) {
// when doing a y-flip we have to iterate through top-to-bottom chunks
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index 7208425..bdbde8f 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -1438,11 +1438,12 @@ TEST_F(GLES2ImplementationTest, ReadPixels2Reads) {
Cmds expected;
expected.read1.Init(
0, 0, kWidth, kHeight / 2, kFormat, kType,
- mem1.id, mem1.offset, result1.id, result1.offset);
+ mem1.id, mem1.offset, result1.id, result1.offset,
+ false);
expected.set_token1.Init(GetNextToken());
expected.read2.Init(
0, kHeight / 2, kWidth, kHeight / 2, kFormat, kType,
- mem2.id, mem2.offset, result2.id, result2.offset);
+ mem2.id, mem2.offset, result2.id, result2.offset, false);
expected.set_token2.Init(GetNextToken());
scoped_ptr<int8[]> buffer(new int8[kWidth * kHeight * kBytesPerPixel]);
@@ -1474,7 +1475,7 @@ TEST_F(GLES2ImplementationTest, ReadPixelsBadFormatType) {
Cmds expected;
expected.read.Init(
0, 0, kWidth, kHeight, kFormat, kType,
- mem1.id, mem1.offset, result1.id, result1.offset);
+ mem1.id, mem1.offset, result1.id, result1.offset, false);
expected.set_token.Init(GetNextToken());
scoped_ptr<int8[]> buffer(new int8[kWidth * kHeight * kBytesPerPixel]);
diff --git a/gpu/command_buffer/client/query_tracker.cc b/gpu/command_buffer/client/query_tracker.cc
index 7cdc7fd..35732bf 100644
--- a/gpu/command_buffer/client/query_tracker.cc
+++ b/gpu/command_buffer/client/query_tracker.cc
@@ -113,9 +113,7 @@ void QueryTracker::Query::Begin(GLES2Implementation* gl) {
gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
break;
case GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM:
- // tell service about id, shared memory and count
- gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
- break;
+ case GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM:
default:
// tell service about id, shared memory and count
gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
@@ -165,8 +163,7 @@ bool QueryTracker::Query::CheckResultsAvailable(
static_cast<uint64>(0xFFFFFFFFL));
break;
case GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM:
- result_ = info_.sync->result;
- break;
+ case GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM:
default:
result_ = info_.sync->result;
break;
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
index c84a363..11b9901 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -4887,7 +4887,7 @@ struct ReadPixels {
void Init(
GLint _x, GLint _y, GLsizei _width, GLsizei _height, GLenum _format,
GLenum _type, uint32 _pixels_shm_id, uint32 _pixels_shm_offset,
- uint32 _result_shm_id, uint32 _result_shm_offset) {
+ uint32 _result_shm_id, uint32 _result_shm_offset, GLboolean _async) {
SetHeader();
x = _x;
y = _y;
@@ -4899,17 +4899,18 @@ struct ReadPixels {
pixels_shm_offset = _pixels_shm_offset;
result_shm_id = _result_shm_id;
result_shm_offset = _result_shm_offset;
+ async = _async;
}
void* Set(
void* cmd, GLint _x, GLint _y, GLsizei _width, GLsizei _height,
GLenum _format, GLenum _type, uint32 _pixels_shm_id,
uint32 _pixels_shm_offset, uint32 _result_shm_id,
- uint32 _result_shm_offset) {
+ uint32 _result_shm_offset, GLboolean _async) {
static_cast<ValueType*>(
cmd)->Init(
_x, _y, _width, _height, _format, _type, _pixels_shm_id,
- _pixels_shm_offset, _result_shm_id, _result_shm_offset);
+ _pixels_shm_offset, _result_shm_id, _result_shm_offset, _async);
return NextCmdAddress<ValueType>(cmd);
}
@@ -4924,10 +4925,11 @@ struct ReadPixels {
uint32 pixels_shm_offset;
uint32 result_shm_id;
uint32 result_shm_offset;
+ uint32 async;
};
-COMPILE_ASSERT(sizeof(ReadPixels) == 44,
- Sizeof_ReadPixels_is_not_44);
+COMPILE_ASSERT(sizeof(ReadPixels) == 48,
+ Sizeof_ReadPixels_is_not_48);
COMPILE_ASSERT(offsetof(ReadPixels, header) == 0,
OffsetOf_ReadPixels_header_not_0);
COMPILE_ASSERT(offsetof(ReadPixels, x) == 4,
@@ -4950,6 +4952,8 @@ COMPILE_ASSERT(offsetof(ReadPixels, result_shm_id) == 36,
OffsetOf_ReadPixels_result_shm_id_not_36);
COMPILE_ASSERT(offsetof(ReadPixels, result_shm_offset) == 40,
OffsetOf_ReadPixels_result_shm_offset_not_40);
+COMPILE_ASSERT(offsetof(ReadPixels, async) == 44,
+ OffsetOf_ReadPixels_async_not_44);
struct ReleaseShaderCompiler {
typedef ReleaseShaderCompiler ValueType;
diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
index 87e426f..740e6cb 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -1803,7 +1803,8 @@ TEST_F(GLES2FormatTest, ReadPixels) {
static_cast<uint32>(17),
static_cast<uint32>(18),
static_cast<uint32>(19),
- static_cast<uint32>(20));
+ static_cast<uint32>(20),
+ static_cast<GLboolean>(21));
EXPECT_EQ(static_cast<uint32>(cmds::ReadPixels::kCmdId),
cmd.header.command);
EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
@@ -1817,6 +1818,7 @@ TEST_F(GLES2FormatTest, ReadPixels) {
EXPECT_EQ(static_cast<uint32>(18), cmd.pixels_shm_offset);
EXPECT_EQ(static_cast<uint32>(19), cmd.result_shm_id);
EXPECT_EQ(static_cast<uint32>(20), cmd.result_shm_offset);
+ EXPECT_EQ(static_cast<GLboolean>(21), cmd.async);
CheckBytesWrittenMatchesExpectedSize(
next_cmd, sizeof(cmd));
}
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
index c2fab6a..573aee9 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
@@ -228,7 +228,7 @@ static const GLES2Util::EnumToString enum_to_string_table[] = {
{ 0x84F5, "GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM", },
{ 0x882A, "GL_DRAW_BUFFER5_NV", },
{ 0x80AA, "GL_SAMPLE_COVERAGE_VALUE", },
- { 0x84F6, "GL_TEXTURE_BINDING_RECTANGLE_ARB", },
+ { 0x84F6, "GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM", },
{ 0x80AB, "GL_SAMPLE_COVERAGE_INVERT", },
{ 0x8FC4, "GL_SHADER_BINARY_VIV", },
{ 0x882B, "GL_DRAW_BUFFER6_NV", },
@@ -1080,6 +1080,8 @@ std::string GLES2Util::GetStringQueryTarget(uint32 value) {
{ GL_LATENCY_QUERY_CHROMIUM, "GL_LATENCY_QUERY_CHROMIUM" },
{ GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM,
"GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM" },
+ { GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM,
+ "GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM" },
};
return GLES2Util::GetQualifiedEnumString(
string_table, arraysize(string_table), value);
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index f759bef..b0fb120 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -119,7 +119,8 @@ FeatureInfo::FeatureFlags::FeatureFlags()
enable_shader_name_hashing(false),
enable_samplers(false),
ext_draw_buffers(false),
- ext_frag_depth(false) {
+ ext_frag_depth(false),
+ use_async_readpixels(false) {
}
FeatureInfo::Workarounds::Workarounds() :
@@ -642,6 +643,16 @@ void FeatureInfo::AddFeatures(const CommandLine& command_line) {
feature_flags_.ext_frag_depth = true;
}
+ bool ui_gl_fence_works =
+ extensions.Contains("GL_NV_fence") ||
+ extensions.Contains("GL_ARB_sync");
+
+ if (ui_gl_fence_works &&
+ extensions.Contains("GL_ARB_pixel_buffer_object") &&
+ !workarounds_.disable_async_readpixels) {
+ feature_flags_.use_async_readpixels = true;
+ }
+
if (!disallowed_features_.swap_buffer_complete_callback)
AddExtensionString("GL_CHROMIUM_swapbuffers_complete_callback");
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h
index de52159..a9ccf64 100644
--- a/gpu/command_buffer/service/feature_info.h
+++ b/gpu/command_buffer/service/feature_info.h
@@ -48,6 +48,7 @@ class GPU_EXPORT FeatureInfo : public base::RefCounted<FeatureInfo> {
bool enable_samplers;
bool ext_draw_buffers;
bool ext_frag_depth;
+ bool use_async_readpixels;
};
struct Workarounds {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 3c49a73..1075b34 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"
@@ -477,6 +478,19 @@ class BackFramebuffer {
DISALLOW_COPY_AND_ASSIGN(BackFramebuffer);
};
+struct FenceCallback {
+ explicit FenceCallback()
+ : fence(gfx::GLFence::Create()) {
+ DCHECK(fence);
+ }
+ void AddCallback(base::Closure cb) {
+ callbacks.push_back(cb);
+ }
+ std::vector<base::Closure> callbacks;
+ scoped_ptr<gfx::GLFence> fence;
+};
+
+
// } // anonymous namespace.
bool GLES2Decoder::GetServiceTextureId(uint32 client_texture_id,
@@ -587,6 +601,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;
@@ -1561,6 +1577,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
@@ -1729,6 +1748,8 @@ class GLES2DecoderImpl : public GLES2Decoder {
scoped_ptr<GPUTracer> gpu_tracer_;
+ std::queue<linked_ptr<FenceCallback> > pending_readpixel_fences_;
+
DISALLOW_COPY_AND_ASSIGN(GLES2DecoderImpl);
};
@@ -2820,6 +2841,7 @@ bool GLES2DecoderImpl::MakeCurrent() {
}
void GLES2DecoderImpl::ProcessFinishedAsyncTransfers() {
+ ProcessPendingReadPixels();
if (engine() && query_manager_.get())
query_manager_->ProcessPendingTransferQueries();
@@ -3548,6 +3570,7 @@ bool GLES2DecoderImpl::CreateShaderHelper(GLenum type, GLuint client_id) {
void GLES2DecoderImpl::DoFinish() {
glFinish();
+ ProcessPendingReadPixels();
ProcessPendingQueries();
}
@@ -6762,6 +6785,96 @@ 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;
+ Result* result = NULL;
+ if (c.result_shm_id != 0) {
+ result = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result));
+ if (!result) {
+ if (buffer != 0) {
+ glDeleteBuffersARB(1, &buffer);
+ }
+ return;
+ }
+ }
+ 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);
+ }
+
+ 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())
@@ -6772,6 +6885,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;
@@ -6871,6 +6985,25 @@ 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);
+ pending_readpixel_fences_.push(linked_ptr<FenceCallback>(
+ new FenceCallback()));
+ 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");
@@ -6878,51 +7011,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;
@@ -9124,11 +9213,35 @@ bool GLES2DecoderImpl::ProcessPendingQueries() {
return query_manager_->HavePendingQueries();
}
+// Note that if there are no pending readpixels right now,
+// this function will call the callback immediately.
+void GLES2DecoderImpl::WaitForReadPixels(base::Closure callback) {
+ if (features().use_async_readpixels && !pending_readpixel_fences_.empty()) {
+ pending_readpixel_fences_.back()->callbacks.push_back(callback);
+ } else {
+ callback.Run();
+ }
+}
+
+void GLES2DecoderImpl::ProcessPendingReadPixels() {
+ while (!pending_readpixel_fences_.empty() &&
+ pending_readpixel_fences_.front()->fence->HasCompleted()) {
+ std::vector<base::Closure> callbacks =
+ pending_readpixel_fences_.front()->callbacks;
+ pending_readpixel_fences_.pop();
+ for (size_t i = 0; i < callbacks.size(); i++) {
+ callbacks[i].Run();
+ }
+ }
+}
+
bool GLES2DecoderImpl::HasMoreIdleWork() {
- return async_pixel_transfer_manager_->NeedsProcessMorePendingTransfers();
+ return !pending_readpixel_fences_.empty() ||
+ async_pixel_transfer_manager_->NeedsProcessMorePendingTransfers();
}
void GLES2DecoderImpl::PerformIdleWork() {
+ ProcessPendingReadPixels();
if (!async_pixel_transfer_manager_->NeedsProcessMorePendingTransfers())
return;
async_pixel_transfer_manager_->ProcessMorePendingTransfers();
@@ -9146,6 +9259,7 @@ error::Error GLES2DecoderImpl::HandleBeginQueryEXT(
case GL_COMMANDS_ISSUED_CHROMIUM:
case GL_LATENCY_QUERY_CHROMIUM:
case GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM:
+ case GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM:
case GL_GET_ERROR_QUERY_CHROMIUM:
break;
default:
@@ -9158,6 +9272,8 @@ error::Error GLES2DecoderImpl::HandleBeginQueryEXT(
break;
}
+ // TODO(hubbe): Make it possible to have one query per type running at the
+ // same time.
if (state_.current_query.get()) {
LOCAL_SET_GL_ERROR(
GL_INVALID_OPERATION, "glBeginQueryEXT", "query already in progress");
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h
index 4f66a62..57445c7 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.h
@@ -213,6 +213,7 @@ class GPU_EXPORT GLES2Decoder : public base::SupportsWeakPtr<GLES2Decoder>,
virtual void SetWaitSyncPointCallback(
const WaitSyncPointCallback& callback) = 0;
+ virtual void WaitForReadPixels(base::Closure callback) = 0;
virtual uint32 GetTextureUploadCount() = 0;
virtual base::TimeDelta GetTotalTextureUploadTime() = 0;
virtual base::TimeDelta GetTotalProcessingCommandsTime() = 0;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
index 5fe0600..e6c497f 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
@@ -102,6 +102,8 @@ class MockGLES2Decoder : public GLES2Decoder {
void(const ShaderCacheCallback& callback));
MOCK_METHOD1(SetWaitSyncPointCallback,
void(const WaitSyncPointCallback& callback));
+ MOCK_METHOD1(WaitForReadPixels,
+ void(base::Closure callback));
MOCK_METHOD0(GetTextureUploadCount, uint32());
MOCK_METHOD0(GetTotalTextureUploadTime, base::TimeDelta());
MOCK_METHOD0(GetTotalProcessingCommandsTime, base::TimeDelta());
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index 09ed184..b426286 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -2316,7 +2316,8 @@ void GLES2DecoderTest::CheckReadPixelsOutOfRange(
cmd.Init(in_read_x, in_read_y, in_read_width, in_read_height,
kFormat, GL_UNSIGNED_BYTE,
pixels_shm_id, pixels_shm_offset,
- result_shm_id, result_shm_offset);
+ result_shm_id, result_shm_offset,
+ false);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
GLint unpadded_row_size = emu.ComputeImageDataSize(in_read_width, 1);
@@ -2393,7 +2394,8 @@ TEST_F(GLES2DecoderTest, ReadPixels) {
ReadPixels cmd;
cmd.Init(0, 0, kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE,
pixels_shm_id, pixels_shm_offset,
- result_shm_id, result_shm_offset);
+ result_shm_id, result_shm_offset,
+ false);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
for (GLint yy = 0; yy < kHeight; ++yy) {
EXPECT_TRUE(emu.CompareRowSegment(
@@ -2440,7 +2442,8 @@ TEST_F(GLES2DecoderRGBBackbufferTest, ReadPixelsNoAlphaBackbuffer) {
ReadPixels cmd;
cmd.Init(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
pixels_shm_id, pixels_shm_offset,
- result_shm_id, result_shm_offset);
+ result_shm_id, result_shm_offset,
+ false);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
for (GLint yy = 0; yy < kHeight; ++yy) {
EXPECT_TRUE(emu.CompareRowSegment(
@@ -2477,34 +2480,41 @@ TEST_F(GLES2DecoderTest, ReadPixelsInvalidArgs) {
ReadPixels cmd;
cmd.Init(0, 0, -1, 1, GL_RGB, GL_UNSIGNED_BYTE,
pixels_shm_id, pixels_shm_offset,
- result_shm_id, result_shm_offset);
+ result_shm_id, result_shm_offset,
+ false);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
cmd.Init(0, 0, 1, -1, GL_RGB, GL_UNSIGNED_BYTE,
pixels_shm_id, pixels_shm_offset,
- result_shm_id, result_shm_offset);
+ result_shm_id, result_shm_offset,
+ false);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
cmd.Init(0, 0, 1, 1, GL_RGB, GL_INT,
pixels_shm_id, pixels_shm_offset,
- result_shm_id, result_shm_offset);
+ result_shm_id, result_shm_offset,
+ false);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
cmd.Init(0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE,
kInvalidSharedMemoryId, pixels_shm_offset,
- result_shm_id, result_shm_offset);
+ result_shm_id, result_shm_offset,
+ false);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE,
pixels_shm_id, kInvalidSharedMemoryOffset,
- result_shm_id, result_shm_offset);
+ result_shm_id, result_shm_offset,
+ false);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE,
pixels_shm_id, pixels_shm_offset,
- kInvalidSharedMemoryId, result_shm_offset);
+ kInvalidSharedMemoryId, result_shm_offset,
+ false);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE,
pixels_shm_id, pixels_shm_offset,
- result_shm_id, kInvalidSharedMemoryOffset);
+ result_shm_id, kInvalidSharedMemoryOffset,
+ false);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
}
@@ -4932,7 +4942,8 @@ TEST_F(GLES2DecoderTest, ReadPixelsGLError) {
ReadPixels cmd;
cmd.Init(x, y, width, height, kFormat, GL_UNSIGNED_BYTE,
pixels_shm_id, pixels_shm_offset,
- result_shm_id, result_shm_offset);
+ result_shm_id, result_shm_offset,
+ false);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
}
@@ -6664,8 +6675,9 @@ TEST_F(GLES2DecoderWithShaderTest, UnClearedAttachmentsGetClearedOnReadPixels) {
uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(*result);
ReadPixels cmd;
cmd.Init(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
- pixels_shm_id, pixels_shm_offset,
- result_shm_id, result_shm_offset);
+ pixels_shm_id, pixels_shm_offset,
+ result_shm_id, result_shm_offset,
+ false);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
@@ -6724,8 +6736,9 @@ TEST_F(GLES2DecoderManualInitTest,
uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(Result);
ReadPixels cmd;
cmd.Init(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
- pixels_shm_id, pixels_shm_offset,
- result_shm_id, result_shm_offset);
+ pixels_shm_id, pixels_shm_offset,
+ result_shm_id, result_shm_offset,
+ false);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
index 444cec3..b8194d9 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
@@ -300,6 +300,7 @@ static const GLenum valid_query_target_table[] = {
GL_COMMANDS_ISSUED_CHROMIUM,
GL_LATENCY_QUERY_CHROMIUM,
GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM,
+ GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM,
};
static const GLenum valid_read_pixel_format_table[] = {
diff --git a/gpu/command_buffer/service/query_manager.cc b/gpu/command_buffer/service/query_manager.cc
index 4af0349..7566099 100644
--- a/gpu/command_buffer/service/query_manager.cc
+++ b/gpu/command_buffer/service/query_manager.cc
@@ -288,6 +288,62 @@ void CommandLatencyQuery::Destroy(bool /* have_context */) {
CommandLatencyQuery::~CommandLatencyQuery() {
}
+
+class AsyncReadPixelsCompletedQuery
+ : public QueryManager::Query,
+ public base::SupportsWeakPtr<AsyncReadPixelsCompletedQuery> {
+ public:
+ AsyncReadPixelsCompletedQuery(
+ QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
+
+ virtual bool Begin() OVERRIDE;
+ virtual bool End(uint32 submit_count) OVERRIDE;
+ virtual bool Process() OVERRIDE;
+ virtual void Destroy(bool have_context) OVERRIDE;
+
+ protected:
+ void Complete();
+ virtual ~AsyncReadPixelsCompletedQuery();
+};
+
+AsyncReadPixelsCompletedQuery::AsyncReadPixelsCompletedQuery(
+ QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
+ : Query(manager, target, shm_id, shm_offset) {
+}
+
+bool AsyncReadPixelsCompletedQuery::Begin() {
+ return true;
+}
+
+bool AsyncReadPixelsCompletedQuery::End(uint32 submit_count) {
+ if (!AddToPendingQueue(submit_count)) {
+ return false;
+ }
+ manager()->decoder()->WaitForReadPixels(
+ base::Bind(&AsyncReadPixelsCompletedQuery::Complete,
+ AsWeakPtr()));
+
+ return true;
+}
+
+void AsyncReadPixelsCompletedQuery::Complete() {
+ MarkAsCompleted(1);
+}
+
+bool AsyncReadPixelsCompletedQuery::Process() {
+ return true;
+}
+
+void AsyncReadPixelsCompletedQuery::Destroy(bool /* have_context */) {
+ if (!IsDeleted()) {
+ MarkAsDeleted();
+ }
+}
+
+AsyncReadPixelsCompletedQuery::~AsyncReadPixelsCompletedQuery() {
+}
+
+
class GetErrorQuery : public QueryManager::Query {
public:
GetErrorQuery(
@@ -379,6 +435,10 @@ QueryManager::Query* QueryManager::CreateQuery(
query = new AsyncPixelTransfersCompletedQuery(
this, target, shm_id, shm_offset);
break;
+ case GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM:
+ query = new AsyncReadPixelsCompletedQuery(
+ this, target, shm_id, shm_offset);
+ break;
case GL_GET_ERROR_QUERY_CHROMIUM:
query = new GetErrorQuery(this, target, shm_id, shm_offset);
break;
diff --git a/gpu/command_buffer/tests/gl_readback_unittests.cc b/gpu/command_buffer/tests/gl_readback_unittests.cc
index e725213..4ebb09a 100644
--- a/gpu/command_buffer/tests/gl_readback_unittests.cc
+++ b/gpu/command_buffer/tests/gl_readback_unittests.cc
@@ -6,6 +6,9 @@
#include <GLES2/gl2ext.h>
#include <GLES2/gl2extchromium.h>
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "gpu/command_buffer/tests/gl_manager.h"
#include "gpu/command_buffer/tests/gl_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -23,38 +26,28 @@ class GLReadbackTest : public testing::Test {
gl_.Destroy();
}
- GLManager gl_;
-};
+ static void WaitForQueryCallback(int q, base::Closure cb) {
+ unsigned int done = 0;
+ glGetQueryObjectuivEXT(q, GL_QUERY_RESULT_AVAILABLE_EXT, &done);
+ if (done) {
+ cb.Run();
+ } else {
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&WaitForQueryCallback, q, cb),
+ base::TimeDelta::FromMilliseconds(3));
+ }
+ }
+ void WaitForQuery(int q) {
+ base::RunLoop run_loop;
+ WaitForQueryCallback(q, run_loop.QuitClosure());
+ run_loop.Run();
+ }
-TEST_F(GLReadbackTest, ReadPixelsWithPBO) {
- const GLint kBytesPerPixel = 4;
- const GLint kWidth = 2;
- const GLint kHeight = 2;
+ GLManager gl_;
+};
- GLuint b;
- glClearColor(0.0, 0.0, 1.0, 1.0);
- glClear(GL_COLOR_BUFFER_BIT);
- glGenBuffers(1, &b);
- glBindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, b);
- glBufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
- kWidth * kHeight * kBytesPerPixel,
- NULL,
- GL_STREAM_READ);
- glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, 0);
- unsigned char *data = static_cast<unsigned char *>(
- glMapBufferCHROMIUM(
- GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
- GL_READ_ONLY));
- EXPECT_TRUE(data);
- EXPECT_EQ(data[0], 0); // red
- EXPECT_EQ(data[1], 0); // green
- EXPECT_EQ(data[2], 255); // blue
- glUnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
- glBindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
- glDeleteBuffers(1, &b);
- GLTestHelper::CheckGLError("no errors", __LINE__);
-}
TEST_F(GLReadbackTest, ReadPixelsWithPBOAndQuery) {
const GLint kBytesPerPixel = 4;
@@ -71,14 +64,11 @@ TEST_F(GLReadbackTest, ReadPixelsWithPBOAndQuery) {
kWidth * kHeight * kBytesPerPixel,
NULL,
GL_STREAM_READ);
- glBeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM, q);
+ glBeginQueryEXT(GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM, q);
glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, 0);
- glEndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM);
+ glEndQueryEXT(GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM);
glFlush();
- unsigned int done = 0;
- while (!done) {
- glGetQueryObjectuivEXT(q, GL_QUERY_RESULT_AVAILABLE_EXT, &done);
- }
+ WaitForQuery(q);
// TODO(hubbe): Check that glMapBufferCHROMIUM does not block here.
unsigned char *data = static_cast<unsigned char *>(
diff --git a/gpu/config/gpu_driver_bug_list_json.cc b/gpu/config/gpu_driver_bug_list_json.cc
index 597fc32..76ea7d2 100644
--- a/gpu/config/gpu_driver_bug_list_json.cc
+++ b/gpu/config/gpu_driver_bug_list_json.cc
@@ -389,8 +389,7 @@ const char kGpuDriverBugListJson[] = LONG_STRING_CONST(
{
"id": 25,
"cr_bugs": [152225],
- "description":
- "Intel OSX drivers prior to mountain lion crashes when using PBOs",
+ "description": "GL_ARB_sync doesn't work on OSX 10.7",
"os": {
"type": "macosx",
"version": {
@@ -398,7 +397,6 @@ const char kGpuDriverBugListJson[] = LONG_STRING_CONST(
"number": "10.8"
}
},
- "vendor_id": "0x8086",
"features": [
"disable_async_readpixels"
]
diff --git a/ui/gl/gl_bindings.h b/ui/gl/gl_bindings.h
index 85fdbfb..c6a1eac 100644
--- a/ui/gl/gl_bindings.h
+++ b/ui/gl/gl_bindings.h
@@ -124,6 +124,7 @@
/* GL_CHROMIUM_async_pixel_transfers */
#define GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM 0x84F5
+#define GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM 0x84F6
// GL_OES_texure_3D
#define GL_SAMPLER_3D_OES 0x8B5F