Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3881)

Unified Diff: gpu/command_buffer/service/gles2_cmd_decoder.cc

Issue 11428140: gpu: Add async pixel transfer interface, stub and tests. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Fix bots. Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 3fc39c6dda1c29f787f7a8648d00baa58d85d481..dfb29e30f62dd75ddbd025595cb526959493b66a 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -56,6 +56,7 @@
#include "gpu/command_buffer/service/texture_manager.h"
#include "gpu/command_buffer/service/vertex_attrib_manager.h"
#include "gpu/command_buffer/service/vertex_array_manager.h"
+#include "ui/gl/async_pixel_transfer_delegate.h"
#include "ui/gl/gl_image.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_surface.h"
@@ -193,6 +194,61 @@ static inline GLenum GetTexInternalFormat(GLenum internal_format) {
return internal_format;
}
+// TODO(epenner): Could the above function be merged into this and removed?
+static inline GLenum GetTexInternalFormat(GLenum internal_format,
+ GLenum format,
+ GLenum type) {
+ GLenum gl_internal_format = GetTexInternalFormat(internal_format);
+
+ if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2)
+ return gl_internal_format;
+
+ if (type == GL_FLOAT) {
+ switch (format) {
+ case GL_RGBA:
+ gl_internal_format = GL_RGBA32F_ARB;
+ break;
+ case GL_RGB:
+ gl_internal_format = GL_RGB32F_ARB;
+ break;
+ case GL_LUMINANCE_ALPHA:
+ gl_internal_format = GL_LUMINANCE_ALPHA32F_ARB;
+ break;
+ case GL_LUMINANCE:
+ gl_internal_format = GL_LUMINANCE32F_ARB;
+ break;
+ case GL_ALPHA:
+ gl_internal_format = GL_ALPHA32F_ARB;
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ } else if (type == GL_HALF_FLOAT_OES) {
+ switch (format) {
+ case GL_RGBA:
+ gl_internal_format = GL_RGBA16F_ARB;
+ break;
+ case GL_RGB:
+ gl_internal_format = GL_RGB16F_ARB;
+ break;
+ case GL_LUMINANCE_ALPHA:
+ gl_internal_format = GL_LUMINANCE_ALPHA16F_ARB;
+ break;
+ case GL_LUMINANCE:
+ gl_internal_format = GL_LUMINANCE16F_ARB;
+ break;
+ case GL_ALPHA:
+ gl_internal_format = GL_ALPHA16F_ARB;
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+ return gl_internal_format;
+}
+
static void WrappedTexImage2D(
GLenum target,
GLint level,
@@ -203,55 +259,9 @@ static void WrappedTexImage2D(
GLenum format,
GLenum type,
const void* pixels) {
- GLenum gl_internal_format = GetTexInternalFormat(internal_format);
- if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
- if (type == GL_FLOAT) {
- switch (format) {
- case GL_RGBA:
- gl_internal_format = GL_RGBA32F_ARB;
- break;
- case GL_RGB:
- gl_internal_format = GL_RGB32F_ARB;
- break;
- case GL_LUMINANCE_ALPHA:
- gl_internal_format = GL_LUMINANCE_ALPHA32F_ARB;
- break;
- case GL_LUMINANCE:
- gl_internal_format = GL_LUMINANCE32F_ARB;
- break;
- case GL_ALPHA:
- gl_internal_format = GL_ALPHA32F_ARB;
- break;
- default:
- NOTREACHED();
- break;
- }
- } else if (type == GL_HALF_FLOAT_OES) {
- switch (format) {
- case GL_RGBA:
- gl_internal_format = GL_RGBA16F_ARB;
- break;
- case GL_RGB:
- gl_internal_format = GL_RGB16F_ARB;
- break;
- case GL_LUMINANCE_ALPHA:
- gl_internal_format = GL_LUMINANCE_ALPHA16F_ARB;
- break;
- case GL_LUMINANCE:
- gl_internal_format = GL_LUMINANCE16F_ARB;
- break;
- case GL_ALPHA:
- gl_internal_format = GL_ALPHA16F_ARB;
- break;
- default:
- NOTREACHED();
- break;
- }
- }
- }
glTexImage2D(
- target, level, gl_internal_format, width, height, border, format, type,
- pixels);
+ target, level, GetTexInternalFormat(internal_format, format, type),
+ width, height, border, format, type, pixels);
}
// Wrapper for glEnable/glDisable that doesn't suck.
@@ -552,6 +562,12 @@ class GLES2DecoderImpl : public GLES2Decoder {
virtual void SetMsgCallback(const MsgCallback& callback) OVERRIDE;
virtual void SetStreamTextureManager(StreamTextureManager* manager) OVERRIDE;
+
+ virtual gfx::AsyncPixelTransferDelegate*
+ GetAsyncPixelTransferDelegate() OVERRIDE;
+ virtual void SetAsyncPixelTransferDelegate(
+ gfx::AsyncPixelTransferDelegate* delegate) OVERRIDE;
+
virtual bool GetServiceTextureId(uint32 client_texture_id,
uint32* service_texture_id) OVERRIDE;
@@ -774,6 +790,14 @@ class GLES2DecoderImpl : public GLES2Decoder {
GLenum type,
const void * data);
+ // Extra validation for async tex(Sub)Image2D.
+ bool ValidateAsyncTransfer(
+ const char* function_name,
+ TextureManager::TextureInfo* info,
+ GLenum target,
+ GLint level,
+ const void * data);
+
// Wrapper for TexImageIOSurface2DCHROMIUM.
void DoTexImageIOSurface2DCHROMIUM(
GLenum target,
@@ -1598,6 +1622,7 @@ class GLES2DecoderImpl : public GLES2Decoder {
MsgCallback msg_callback_;
StreamTextureManager* stream_texture_manager_;
+ scoped_ptr<gfx::AsyncPixelTransferDelegate> async_pixel_transfer_delegate_;
// The format of the back buffer_
GLenum back_buffer_color_format_;
@@ -2390,6 +2415,10 @@ bool GLES2DecoderImpl::Initialize(
glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT);
}
+ // Create a delegate to perform async pixel transfers.
+ async_pixel_transfer_delegate_ =
+ gfx::AsyncPixelTransferDelegate::Create(context.get());
+
return true;
}
@@ -2721,6 +2750,27 @@ void GLES2DecoderImpl::RestoreCurrentTexture2DBindings() {
bool GLES2DecoderImpl::CheckFramebufferValid(
FramebufferManager::FramebufferInfo* framebuffer,
GLenum target, const char* func_name) {
+
+ // As this occurs before every draw, take this opportunity to
+ // bind any unbound async pixel transfers to their textures.
+ // TODO(epenner): Is there a better place to do this? Transfers
greggman 2012/12/14 06:08:06 This seems like it really needs to be in DoCommand
epenner 2012/12/14 21:01:34 Does DoCommand happen at every GL command? It only
+ // are marked as complete on the main thread, so we only need
+ // to process them once in a given main-thread task.
+ bool frame_buffer_dirty = false;
+ bool texture_dirty = false;
+ GetContextGroup()->texture_manager()->BindFinishedAsyncPixelTransfers(
greggman 2012/12/14 06:08:06 you can just use texture_manager()->BindFinished.
epenner 2012/12/14 21:01:34 Done.
+ &texture_dirty, &frame_buffer_dirty);
+ // Texture unit zero might be stomped.
+ if (texture_dirty)
+ RestoreCurrentTexture2DBindings();
+ // A texture attached to frame-buffer might have changed size.
+ if (frame_buffer_dirty) {
+ clear_state_dirty_ = true;
+ // TODO(gman): If textures tracked which framebuffers they were attached to
+ // we could just mark those framebuffers as not complete.
+ framebuffer_manager()->IncFramebufferStateChangeCount();
+ }
+
if (!framebuffer) {
if (backbuffer_needs_clear_bits_) {
glClearColor(0, 0, 0, (GLES2Util::GetChannelsForFormat(
@@ -2887,6 +2937,16 @@ void GLES2DecoderImpl::SetStreamTextureManager(StreamTextureManager* manager) {
stream_texture_manager_ = manager;
}
+gfx::AsyncPixelTransferDelegate*
+ GLES2DecoderImpl::GetAsyncPixelTransferDelegate() {
+ return async_pixel_transfer_delegate_.get();
+}
+
+void GLES2DecoderImpl::SetAsyncPixelTransferDelegate(
+ gfx::AsyncPixelTransferDelegate* delegate) {
+ async_pixel_transfer_delegate_ = make_scoped_ptr(delegate);
+}
+
bool GLES2DecoderImpl::GetServiceTextureId(uint32 client_texture_id,
uint32* service_texture_id) {
TextureManager::TextureInfo* texture =
@@ -3629,6 +3689,7 @@ void GLES2DecoderImpl::DoBindTexture(GLenum target, GLuint client_id) {
texture_manager()->SetInfoTarget(info, target);
}
glBindTexture(target, info->service_id());
+
TextureUnit& unit = state_.texture_units[state_.active_texture_unit];
unit.bind_target = target;
switch (target) {
@@ -9666,13 +9727,39 @@ void GLES2DecoderImpl::DoTraceEndCHROMIUM() {
gpu_trace_stack_.pop();
}
+bool GLES2DecoderImpl::ValidateAsyncTransfer(
+ const char* function_name,
+ TextureManager::TextureInfo* info,
+ GLenum target,
+ GLint level,
+ const void * data) {
+ // We only support async uploads to 2D textures for now.
+ if (GL_TEXTURE_2D != target) {
+ SetGLErrorInvalidEnum(function_name, target, "target");
+ return false;
+ }
+ // We only support uploads to level zero for now.
+ if (level != 0) {
+ SetGLError(GL_INVALID_VALUE, function_name, "level != 0");
+ return false;
+ }
+ // A transfer buffer must be bound, even for asyncTexImage2D.
+ if (data == NULL) {
+ SetGLError(GL_INVALID_OPERATION, function_name, "buffer == 0");
+ return false;
+ }
+ // We only support one async transfer in progress.
+ if (!info || info->AsyncTransferIsInProgress()) {
+ SetGLError(GL_INVALID_OPERATION,
+ function_name, "transfer already in progress");
+ return false;
+ }
+ return true;
+}
+
error::Error GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM(
uint32 immediate_data_size, const gles2::AsyncTexImage2DCHROMIUM& c) {
TRACE_EVENT0("gpu", "GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM");
-
- // TODO: This is a copy of HandleTexImage2D validation. Merge
- // as much of it as possible.
- tex_image_2d_failed_ = true;
GLenum target = static_cast<GLenum>(c.target);
GLint level = static_cast<GLint>(c.level);
GLint internal_format = static_cast<GLint>(c.internalformat);
@@ -9684,6 +9771,9 @@ error::Error GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM(
uint32 pixels_shm_id = static_cast<uint32>(c.pixels_shm_id);
uint32 pixels_shm_offset = static_cast<uint32>(c.pixels_shm_offset);
uint32 pixels_size;
+
+ // TODO(epenner): Move this and copies of this memory validation
+ // into ValidateTexImage2D step.
if (!GLES2Util::ComputeImageDataSizes(
width, height, format, type, state_.unpack_alignment, &pixels_size, NULL,
NULL)) {
@@ -9698,19 +9788,62 @@ error::Error GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM(
}
}
- // TODO(epenner): Do this via an async task.
- DoTexImage2D(
- target, level, internal_format, width, height, border, format, type,
- pixels, pixels_size);
+ // All the normal glTexSubImage2D validation.
+ if (!ValidateTexImage2D("glAsyncTexImage2D", target, level, internal_format,
greggman 2012/12/14 06:08:06 s/glAsyncTexImage2D/glAsyncTexImage2DCHROMIUM/ s/g
epenner 2012/12/14 21:01:34 Done.
+ width, height, border, format, type, pixels, pixels_size)) {
+ return error::kNoError;
+ }
+
+ // Extra async validation.
+ TextureManager::TextureInfo* info = GetTextureInfoForTarget(target);
+ if (!ValidateAsyncTransfer("glAsyncTexImage2D", info, target, level, pixels))
+ return error::kNoError;
+
+ // Don't allow async redefinition of a textures.
+ if (info->IsDefined()) {
+ SetGLError(GL_INVALID_OPERATION, "glAsyncTexImage2D", "already defined");
+ return error::kNoError;
+ }
+
+ // We know the memory/size is safe, so get the real shared memory since
+ // it might need to be duped to prevent use-after-free of the memory.
+ Buffer buffer = GetSharedMemoryBuffer(c.pixels_shm_id);
+ base::SharedMemory* shared_memory = buffer.shared_memory;
+ uint32 shm_size = buffer.size;
+ uint32 shm_data_offset = c.pixels_shm_offset;
+ uint32 shm_data_size = pixels_size;
+
+ // Set up the async state if needed, and make the texture
+ // immutable so the async state stays valid. The level info
+ // is set up lazily when the transfer completes.
+ DCHECK(!info->GetAsyncTransferState());
+ info->SetAsyncTransferState(
+ async_pixel_transfer_delegate_->
+ CreatePixelTransferState(info->service_id()));
+ info->SetImmutable(true);
+
+ // Issue the async call and set up the texture.
+ GLenum gl_internal_format =
+ GetTexInternalFormat(internal_format, format, type);
+ gfx::AsyncTexImage2DParams tex_params = {target, level, gl_internal_format,
+ width, height, border, format, type};
+ gfx::AsyncMemoryParams mem_params = {shared_memory, shm_size,
+ shm_data_offset, shm_data_size};
+
+ // Add a pending transfer to the texture manager, which will bind the
+ // transfer data to the texture and set the level info at the same time,
+ // after the the transfer is complete.
+ GetContextGroup()->texture_manager()->AddPendingAsyncPixelTransfer(
greggman 2012/12/14 06:08:06 GetConextGroup()-> not needed?
epenner 2012/12/14 21:01:34 Done.
+ info->GetAsyncTransferState()->AsWeakPtr(), info);
+
+ async_pixel_transfer_delegate_->AsyncTexImage2D(
+ info->GetAsyncTransferState(), tex_params, mem_params);
return error::kNoError;
}
error::Error GLES2DecoderImpl::HandleAsyncTexSubImage2DCHROMIUM(
uint32 immediate_data_size, const gles2::AsyncTexSubImage2DCHROMIUM& c) {
TRACE_EVENT0("gpu", "GLES2DecoderImpl::HandleAsyncTexSubImage2DCHROMIUM");
-
- // TODO: This is a copy of HandleTexSubImage2D validation. Merge
- // as much of it as possible.
GLenum target = static_cast<GLenum>(c.target);
GLint level = static_cast<GLint>(c.level);
GLint xoffset = static_cast<GLint>(c.xoffset);
@@ -9719,6 +9852,9 @@ error::Error GLES2DecoderImpl::HandleAsyncTexSubImage2DCHROMIUM(
GLsizei height = static_cast<GLsizei>(c.height);
GLenum format = static_cast<GLenum>(c.format);
GLenum type = static_cast<GLenum>(c.type);
+
+ // TODO(epenner): Move this and copies of this memory validation
+ // into ValidateTexSubImage2D step.
uint32 data_size;
if (!GLES2Util::ComputeImageDataSizes(
width, height, format, type, state_.unpack_alignment, &data_size,
@@ -9727,13 +9863,58 @@ error::Error GLES2DecoderImpl::HandleAsyncTexSubImage2DCHROMIUM(
}
const void* pixels = GetSharedMemoryAs<const void*>(
c.data_shm_id, c.data_shm_offset, data_size);
- if (pixels == NULL) {
- return error::kOutOfBounds;
+
+ // All the normal glTexSubImage2D validation.
+ error::Error error = error::kNoError;
+ if (!ValidateTexSubImage2D(&error, "glAsyncTexSubImage2D", target, level,
+ xoffset, yoffset, width, height, format, type, pixels)) {
+ return error;
}
- // TODO(epenner): Do this via an async task.
- return DoTexSubImage2D(
- target, level, xoffset, yoffset, width, height, format, type, pixels);
+ // Extra async validation.
+ TextureManager::TextureInfo* info = GetTextureInfoForTarget(target);
+ if (!ValidateAsyncTransfer(
+ "glAsyncTexSubImage2D", info, target, level, pixels))
+ return error::kNoError;
+
+ // Guarantee async textures are always 'cleared' as follows:
+ // - AsyncTexImage2D can not redefine an existing texture
+ // - AsyncTexImage2D must initialize the entire image via non-null buffer.
+ // - AsyncTexSubImage2D clears synchronously if not already cleared.
+ // - Textures become immutable after an async call.
+ // This way we know in all cases that an async texture is always clear.
+ if (!info->SafeToRenderFrom()) {
+ if (!texture_manager()->ClearTextureLevel(this, info, target, level)) {
+ SetGLError(
+ GL_OUT_OF_MEMORY, "glAsyncTexSubImage2D", "dimensions too big");
+ return error::kNoError;
+ }
+ }
+
+ // We know the memory/size is safe, so get the real shared memory since
+ // it might need to be duped to prevent use-after-free of the memory.
+ Buffer buffer = GetSharedMemoryBuffer(c.data_shm_id);
+ base::SharedMemory* shared_memory = buffer.shared_memory;
+ uint32 shm_size = buffer.size;
+ uint32 shm_data_offset = c.data_shm_offset;
+ uint32 shm_data_size = data_size;
+
+ if (!info->GetAsyncTransferState()) {
+ // Set up the async state if needed, and make the texture
+ // immutable so the async state stays valid.
+ info->SetAsyncTransferState(
+ async_pixel_transfer_delegate_->
+ CreatePixelTransferState(info->service_id()));
+ info->SetImmutable(true);
+ }
+
+ gfx::AsyncTexSubImage2DParams tex_params = {target, level, xoffset, yoffset,
+ width, height, format, type};
+ gfx::AsyncMemoryParams mem_params = {shared_memory, shm_size,
+ shm_data_offset, shm_data_size};
+ async_pixel_transfer_delegate_->AsyncTexSubImage2D(
+ info->GetAsyncTransferState(), tex_params, mem_params);
+ return error::kNoError;
}
// Include the auto-generated part of this file. We split this because it means

Powered by Google App Engine
This is Rietveld 408576698