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 2ec1e96e4a4fbe30f2a81b4996002b4cd88976d3..5f5ba3c8bf89bd09174c93c4ae42f26f7d63ebeb 100644 |
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc |
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc |
@@ -55,6 +55,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" |
@@ -3505,10 +3506,32 @@ void GLES2DecoderImpl::DoBindTexture(GLenum target, GLuint client_id) { |
"glBindTexture", "illegal target for stream texture."); |
return; |
} |
- if (info->target() == 0) { |
- texture_manager()->SetInfoTarget(info, target); |
+ |
+ if (!info->IsAsyncTransferTexture()) { |
+ if (info->target() == 0) { |
+ texture_manager()->SetInfoTarget(info, target); |
+ } |
+ glBindTexture(target, info->service_id()); |
+ } else { |
+ // If the texture has async transfers, they must be complete. |
+ if (info->AsyncTransferIsInProgress()) { |
greggman
2012/12/05 02:23:42
Why is this needed? Binding a texture should not b
epenner
2012/12/05 04:01:54
Good point! I was trying to preserve the 'level cl
epenner
2012/12/08 03:15:04
Done.
|
+ SetGLError(GL_INVALID_OPERATION, |
+ "glBindTexture", "async transfer already in progress"); |
+ return; |
+ } |
+ |
+ if (info->target() == 0) { |
+ texture_manager()->SetInfoTarget(info, target); |
+ } |
+ |
+ // Bind the GL texture, and perform any custom binding. |
+ info->BindAsyncTransferTexture(target); |
+ |
+ // We now know the transfer texture is cleared. |
+ texture_manager()->SetLevelCleared(info, target, 0); |
} |
- glBindTexture(target, info->service_id()); |
+ |
+ |
TextureUnit& unit = state_.texture_units[state_.active_texture_unit]; |
unit.bind_target = target; |
switch (target) { |
@@ -9347,10 +9370,31 @@ error::Error GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM( |
} |
} |
- // TODO(epenner): Do this via an async task. |
- return DoTexImage2D( |
- target, level, internal_format, width, height, border, format, type, |
- pixels, pixels_size); |
+ // We only support async uploads to 2D textures for now. |
+ if (target != GL_TEXTURE_2D) { |
+ SetGLErrorInvalidEnum("glTexSubImage2D", type, "type"); |
+ return error::kNoError; |
+ } |
+ |
+ // We only support uploads to level zero for now. |
+ if (level != 0) { |
+ SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "level != 0"); |
+ return error::kNoError; |
+ } |
+ |
+ // We only support one async transfer in progress. |
+ TextureManager::TextureInfo* info = GetTextureInfoForTarget(target); |
+ if (!info || info->AsyncTransferState()->TransferIsInProgress()) { |
+ SetGLError(GL_INVALID_OPERATION, |
+ "glAsyncTexImage2D", "transfer already in progress"); |
+ } |
+ |
+ // TODO(epenner): Fix the use-after-free vulnerability here |
+ // by referencing the shared memory for "pixels" until completion. |
+ gfx::AsyncPixelTransferDelegate::Get()->AsyncTexImage2D( |
+ info->AsyncTransferState(), target, level, internal_format, |
+ width, height, border, format, type, pixels); |
+ return error::kNoError; |
} |
error::Error GLES2DecoderImpl::HandleAsyncTexSubImage2DCHROMIUM( |
@@ -9395,13 +9439,49 @@ error::Error GLES2DecoderImpl::HandleAsyncTexSubImage2DCHROMIUM( |
SetGLErrorInvalidEnum("glTexSubImage2D", type, "type"); |
return error::kNoError; |
} |
- if (pixels == NULL) { |
- return error::kOutOfBounds; |
+ |
+ // We only support async uploads to 2D textures for now. |
+ if (target != GL_TEXTURE_2D) { |
+ SetGLErrorInvalidEnum("glTexSubImage2D", type, "type"); |
+ return error::kNoError; |
} |
- // TODO(epenner): Do this via an async task. |
- DoTexSubImage2D( |
- target, level, xoffset, yoffset, width, height, format, type, pixels); |
+ // We only support uploads to level zero for now. |
+ if (level != 0) { |
+ SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "level != 0"); |
+ return error::kNoError; |
+ } |
+ |
+ // We only support one async transfer in progress. |
+ TextureManager::TextureInfo* info = GetTextureInfoForTarget(target); |
+ if (!info || info->AsyncTransferState()->TransferIsInProgress()) { |
+ SetGLError(GL_INVALID_OPERATION, |
+ "glTexSubImage2D", "transfer already in progress"); |
+ } |
+ |
+ // It would be nice to do this async as well, but that way we can't |
+ // be sure the texture is cleared after this call. So better to do it |
+ // immediately (it's easy to avoid this penalty anyway). |
+ GLsizei tex_width = 0; |
+ GLsizei tex_height = 0; |
+ bool ok = info->GetLevelSize(target, level, &tex_width, &tex_height); |
+ DCHECK(ok); |
+ if (xoffset != 0 || yoffset != 0 || |
+ width != tex_width || height != tex_height) { |
+ if (!texture_manager()->ClearTextureLevel(this, info, target, level)) { |
+ SetGLError(GL_OUT_OF_MEMORY, "glTexSubImage2D", "dimensions too big"); |
+ return error::kNoError; |
+ } |
+ // The level is certainly cleared now. In the full update case |
+ // we wait until the texture is used to mark it as cleared. |
+ texture_manager()->SetLevelCleared(info, target, level); |
+ } |
+ |
+ // TODO(epenner): Fix the use-after-free vulnerability here |
+ // by referencing the shared memory for "pixels" until completion. |
+ gfx::AsyncPixelTransferDelegate::Get()->AsyncTexSubImage2D( |
+ info->AsyncTransferState(), target, level, xoffset, yoffset, |
+ width, height, format, type, pixels); |
return error::kNoError; |
} |