Index: gpu/command_buffer/client/gles2_implementation.cc |
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc |
index ccbb45745169eaf0ca7a319281a891c6a20acfc4..2b4cc9e76b010bb648490a39bd8fc296e841a4d1 100644 |
--- a/gpu/command_buffer/client/gles2_implementation.cc |
+++ b/gpu/command_buffer/client/gles2_implementation.cc |
@@ -8,6 +8,7 @@ |
#include <GLES2/gl2ext.h> |
#include <GLES2/gl2extchromium.h> |
+#include <GLES3/gl3.h> |
#include <algorithm> |
#include <limits> |
#include <map> |
@@ -77,8 +78,10 @@ GLES2Implementation::GLES2Implementation( |
unpack_alignment_(4), |
unpack_flip_y_(false), |
unpack_row_length_(0), |
+ unpack_image_height_(0), |
unpack_skip_rows_(0), |
unpack_skip_pixels_(0), |
+ unpack_skip_images_(0), |
pack_reverse_row_order_(false), |
active_texture_unit_(0), |
bound_framebuffer_(0), |
@@ -99,6 +102,7 @@ GLES2Implementation::GLES2Implementation( |
support_client_side_arrays_(support_client_side_arrays), |
use_count_(0), |
error_message_callback_(NULL), |
+ current_trace_stack_(0), |
gpu_control_(gpu_control), |
capabilities_(gpu_control->GetCapabilities()), |
weak_ptr_factory_(this) { |
@@ -1105,12 +1109,18 @@ void GLES2Implementation::PixelStorei(GLenum pname, GLint param) { |
case GL_UNPACK_ROW_LENGTH_EXT: |
unpack_row_length_ = param; |
return; |
+ case GL_UNPACK_IMAGE_HEIGHT: |
+ unpack_image_height_ = param; |
+ return; |
case GL_UNPACK_SKIP_ROWS_EXT: |
unpack_skip_rows_ = param; |
return; |
case GL_UNPACK_SKIP_PIXELS_EXT: |
unpack_skip_pixels_ = param; |
return; |
+ case GL_UNPACK_SKIP_IMAGES: |
+ unpack_skip_images_ = param; |
+ return; |
case GL_UNPACK_FLIP_Y_CHROMIUM: |
unpack_flip_y_ = (param != 0); |
break; |
@@ -1611,7 +1621,7 @@ void GLES2Implementation::TexImage2D( |
uint32 unpadded_row_size; |
uint32 padded_row_size; |
if (!GLES2Util::ComputeImageDataSizes( |
- width, height, format, type, unpack_alignment_, &size, |
+ width, height, 1, format, type, unpack_alignment_, &size, |
&unpadded_row_size, &padded_row_size)) { |
SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large"); |
return; |
@@ -1692,6 +1702,126 @@ void GLES2Implementation::TexImage2D( |
CheckGLError(); |
} |
+void GLES2Implementation::TexImage3D( |
+ GLenum target, GLint level, GLint internalformat, GLsizei width, |
+ GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, |
+ const void* pixels) { |
+ GPU_CLIENT_SINGLE_THREAD_CHECK(); |
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage3D(" |
+ << GLES2Util::GetStringTextureTarget(target) << ", " |
+ << level << ", " |
+ << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", " |
+ << width << ", " << height << ", " << depth << ", " << border << ", " |
+ << GLES2Util::GetStringTextureFormat(format) << ", " |
+ << GLES2Util::GetStringPixelType(type) << ", " |
+ << static_cast<const void*>(pixels) << ")"); |
+ if (level < 0 || height < 0 || width < 0 || depth < 0) { |
+ SetGLError(GL_INVALID_VALUE, "glTexImage3D", "dimension < 0"); |
+ return; |
+ } |
+ if (border != 0) { |
+ SetGLError(GL_INVALID_VALUE, "glTexImage3D", "border != 0"); |
+ return; |
+ } |
+ uint32 size; |
+ uint32 unpadded_row_size; |
+ uint32 padded_row_size; |
+ if (!GLES2Util::ComputeImageDataSizes( |
+ width, height, depth, format, type, unpack_alignment_, &size, |
+ &unpadded_row_size, &padded_row_size)) { |
+ SetGLError(GL_INVALID_VALUE, "glTexImage3D", "image size too large"); |
+ return; |
+ } |
+ |
+ // If there's a pixel unpack buffer bound use it when issuing TexImage3D. |
+ if (bound_pixel_unpack_transfer_buffer_id_) { |
+ GLuint offset = ToGLuint(pixels); |
+ BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid( |
+ bound_pixel_unpack_transfer_buffer_id_, |
+ "glTexImage3D", offset, size); |
+ if (buffer && buffer->shm_id() != -1) { |
+ helper_->TexImage3D( |
+ target, level, internalformat, width, height, depth, format, type, |
+ buffer->shm_id(), buffer->shm_offset() + offset); |
+ buffer->set_last_usage_token(helper_->InsertToken()); |
+ CheckGLError(); |
+ } |
+ return; |
+ } |
+ |
+ // If there's no data just issue TexImage3D |
+ if (!pixels) { |
+ helper_->TexImage3D( |
+ target, level, internalformat, width, height, depth, format, type, |
+ 0, 0); |
+ CheckGLError(); |
+ return; |
+ } |
+ |
+ // compute the advance bytes per row for the src pixels |
+ uint32 src_padded_row_size; |
+ if (unpack_row_length_ > 0) { |
+ if (!GLES2Util::ComputeImagePaddedRowSize( |
+ unpack_row_length_, format, type, unpack_alignment_, |
+ &src_padded_row_size)) { |
+ SetGLError( |
+ GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large"); |
+ return; |
+ } |
+ } else { |
+ src_padded_row_size = padded_row_size; |
+ } |
+ uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height; |
+ |
+ // advance pixels pointer past the skip images/rows/pixels |
+ pixels = reinterpret_cast<const int8*>(pixels) + |
+ unpack_skip_images_ * src_padded_row_size * src_height + |
+ unpack_skip_rows_ * src_padded_row_size; |
+ if (unpack_skip_pixels_) { |
+ uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type); |
+ pixels = reinterpret_cast<const int8*>(pixels) + |
+ unpack_skip_pixels_ * group_size; |
+ } |
+ |
+ // Check if we can send it all at once. |
+ ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_); |
+ if (!buffer.valid()) { |
+ return; |
+ } |
+ |
+ if (buffer.size() >= size) { |
+ void* buffer_pointer = buffer.address(); |
+ for (GLsizei z = 0; z < depth; ++z) { |
+ // Only the last row of the last image is unpadded. |
+ uint32 src_unpadded_row_size = |
+ (z == depth - 1) ? unpadded_row_size : src_padded_row_size; |
+ // TODO(zmo): Ignore flip_y flag for now. |
+ CopyRectToBuffer( |
+ pixels, height, src_unpadded_row_size, src_padded_row_size, false, |
+ buffer_pointer, padded_row_size); |
+ pixels = reinterpret_cast<const int8*>(pixels) + |
+ src_padded_row_size * src_height; |
+ buffer_pointer = reinterpret_cast<int8*>(buffer_pointer) + |
+ padded_row_size * height; |
+ } |
+ helper_->TexImage3D( |
+ target, level, internalformat, width, height, depth, format, type, |
+ buffer.shm_id(), buffer.offset()); |
+ CheckGLError(); |
+ return; |
+ } |
+ |
+ // No, so send it using TexSubImage3D. |
+ helper_->TexImage3D( |
+ target, level, internalformat, width, height, depth, format, type, |
+ 0, 0); |
+ TexSubImage3DImpl( |
+ target, level, 0, 0, 0, width, height, depth, format, type, |
+ unpadded_row_size, pixels, src_padded_row_size, GL_TRUE, &buffer, |
+ padded_row_size); |
+ CheckGLError(); |
+} |
+ |
void GLES2Implementation::TexSubImage2D( |
GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, |
GLsizei height, GLenum format, GLenum type, const void* pixels) { |
@@ -1717,7 +1847,7 @@ void GLES2Implementation::TexSubImage2D( |
uint32 unpadded_row_size; |
uint32 padded_row_size; |
if (!GLES2Util::ComputeImageDataSizes( |
- width, height, format, type, unpack_alignment_, &temp_size, |
+ width, height, 1, format, type, unpack_alignment_, &temp_size, |
&unpadded_row_size, &padded_row_size)) { |
SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large"); |
return; |
@@ -1770,15 +1900,100 @@ void GLES2Implementation::TexSubImage2D( |
CheckGLError(); |
} |
+void GLES2Implementation::TexSubImage3D( |
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, |
+ GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, |
+ const void* pixels) { |
+ GPU_CLIENT_SINGLE_THREAD_CHECK(); |
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage3D(" |
+ << GLES2Util::GetStringTextureTarget(target) << ", " |
+ << level << ", " |
+ << xoffset << ", " << yoffset << ", " << zoffset << ", " |
+ << width << ", " << height << ", " << depth << ", " |
+ << GLES2Util::GetStringTextureFormat(format) << ", " |
+ << GLES2Util::GetStringPixelType(type) << ", " |
+ << static_cast<const void*>(pixels) << ")"); |
+ |
+ if (level < 0 || height < 0 || width < 0 || depth < 0) { |
+ SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "dimension < 0"); |
+ return; |
+ } |
+ if (height == 0 || width == 0 || depth == 0) { |
+ return; |
+ } |
+ |
+ uint32 temp_size; |
+ uint32 unpadded_row_size; |
+ uint32 padded_row_size; |
+ if (!GLES2Util::ComputeImageDataSizes( |
+ width, height, depth, format, type, unpack_alignment_, &temp_size, |
+ &unpadded_row_size, &padded_row_size)) { |
+ SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "size to large"); |
+ return; |
+ } |
+ |
+ // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D. |
+ if (bound_pixel_unpack_transfer_buffer_id_) { |
+ GLuint offset = ToGLuint(pixels); |
+ BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid( |
+ bound_pixel_unpack_transfer_buffer_id_, |
+ "glTexSubImage3D", offset, temp_size); |
+ if (buffer && buffer->shm_id() != -1) { |
+ helper_->TexSubImage3D( |
+ target, level, xoffset, yoffset, zoffset, width, height, depth, |
+ format, type, buffer->shm_id(), buffer->shm_offset() + offset, false); |
+ buffer->set_last_usage_token(helper_->InsertToken()); |
+ CheckGLError(); |
+ } |
+ return; |
+ } |
+ |
+ // compute the advance bytes per row for the src pixels |
+ uint32 src_padded_row_size; |
+ if (unpack_row_length_ > 0) { |
+ if (!GLES2Util::ComputeImagePaddedRowSize( |
+ unpack_row_length_, format, type, unpack_alignment_, |
+ &src_padded_row_size)) { |
+ SetGLError( |
+ GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large"); |
+ return; |
+ } |
+ } else { |
+ src_padded_row_size = padded_row_size; |
+ } |
+ uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height; |
+ |
+ // advance pixels pointer past the skip images/rows/pixels |
+ pixels = reinterpret_cast<const int8*>(pixels) + |
+ unpack_skip_images_ * src_padded_row_size * src_height + |
+ unpack_skip_rows_ * src_padded_row_size; |
+ if (unpack_skip_pixels_) { |
+ uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type); |
+ pixels = reinterpret_cast<const int8*>(pixels) + |
+ unpack_skip_pixels_ * group_size; |
+ } |
+ |
+ ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_); |
+ TexSubImage3DImpl( |
+ target, level, xoffset, yoffset, zoffset, width, height, depth, |
+ format, type, unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, |
+ &buffer, padded_row_size); |
+ CheckGLError(); |
+} |
+ |
static GLint ComputeNumRowsThatFitInBuffer( |
uint32 padded_row_size, uint32 unpadded_row_size, |
- unsigned int size) { |
+ unsigned int size, GLsizei remaining_rows) { |
DCHECK_GE(unpadded_row_size, 0u); |
if (padded_row_size == 0) { |
return 1; |
} |
GLint num_rows = size / padded_row_size; |
- return num_rows + (size - num_rows * padded_row_size) / unpadded_row_size; |
+ if (num_rows + 1 == remaining_rows && |
+ size - num_rows * padded_row_size >= unpadded_row_size) { |
+ num_rows++; |
+ } |
+ return num_rows; |
} |
void GLES2Implementation::TexSubImage2DImpl( |
@@ -1805,7 +2020,7 @@ void GLES2Implementation::TexSubImage2DImpl( |
} |
GLint num_rows = ComputeNumRowsThatFitInBuffer( |
- buffer_padded_row_size, unpadded_row_size, buffer->size()); |
+ buffer_padded_row_size, unpadded_row_size, buffer->size(), height); |
num_rows = std::min(num_rows, height); |
CopyRectToBuffer( |
source, num_rows, unpadded_row_size, pixels_padded_row_size, |
@@ -1821,6 +2036,119 @@ void GLES2Implementation::TexSubImage2DImpl( |
} |
} |
+void GLES2Implementation::TexSubImage3DImpl( |
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei zoffset, |
+ GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, |
+ uint32 unpadded_row_size, const void* pixels, uint32 pixels_padded_row_size, |
+ GLboolean internal, ScopedTransferBufferPtr* buffer, |
+ uint32 buffer_padded_row_size) { |
+ DCHECK(buffer); |
+ DCHECK_GE(level, 0); |
+ DCHECK_GT(height, 0); |
+ DCHECK_GT(width, 0); |
+ DCHECK_GT(depth, 0); |
+ const int8* source = reinterpret_cast<const int8*>(pixels); |
+ GLsizei total_rows = height * depth; |
+ GLint row_index = 0, depth_index = 0; |
+ while (total_rows) { |
+ // Each time, we either copy one or more images, or copy one or more rows |
+ // within a single image, depending on the buffer size limit. |
+ GLsizei max_rows; |
+ unsigned int desired_size; |
+ if (row_index > 0) { |
+ // We are in the middle of an image. Send the remaining of the image. |
+ max_rows = height - row_index; |
+ if (total_rows <= height) { |
+ // Last image, so last row is unpadded. |
+ desired_size = buffer_padded_row_size * (max_rows - 1) + |
+ unpadded_row_size; |
+ } else { |
+ desired_size = buffer_padded_row_size * max_rows; |
+ } |
+ } else { |
+ // Send all the remaining data if possible. |
+ max_rows = total_rows; |
+ desired_size = |
+ buffer_padded_row_size * (max_rows - 1) + unpadded_row_size; |
+ } |
+ if (!buffer->valid() || buffer->size() == 0) { |
+ buffer->Reset(desired_size); |
+ if (!buffer->valid()) { |
+ return; |
+ } |
+ } |
+ GLint num_rows = ComputeNumRowsThatFitInBuffer( |
+ buffer_padded_row_size, unpadded_row_size, buffer->size(), total_rows); |
+ num_rows = std::min(num_rows, max_rows); |
+ GLint num_images = num_rows / height; |
+ GLsizei my_height, my_depth; |
+ if (num_images > 0) { |
+ num_rows = num_images * height; |
+ my_height = height; |
+ my_depth = num_images; |
+ } else { |
+ my_height = num_rows; |
+ my_depth = 1; |
+ } |
+ |
+ // TODO(zmo): Ignore flip_y flag for now. |
+ if (num_images > 0) { |
+ int8* buffer_pointer = reinterpret_cast<int8*>(buffer->address()); |
+ uint32 src_height = |
+ unpack_image_height_ > 0 ? unpack_image_height_ : height; |
+ uint32 image_size_dst = buffer_padded_row_size * height; |
+ uint32 image_size_src = pixels_padded_row_size * src_height; |
+ for (GLint ii = 0; ii < num_images; ++ii) { |
+ uint32 my_unpadded_row_size; |
+ if (total_rows == num_rows && ii + 1 == num_images) |
+ my_unpadded_row_size = unpadded_row_size; |
+ else |
+ my_unpadded_row_size = pixels_padded_row_size; |
+ CopyRectToBuffer( |
+ source + ii * image_size_src, my_height, my_unpadded_row_size, |
+ pixels_padded_row_size, false, buffer_pointer + ii * image_size_dst, |
+ buffer_padded_row_size); |
+ } |
+ } else { |
+ uint32 my_unpadded_row_size; |
+ if (total_rows == num_rows) |
+ my_unpadded_row_size = unpadded_row_size; |
+ else |
+ my_unpadded_row_size = pixels_padded_row_size; |
+ CopyRectToBuffer( |
+ source, my_height, my_unpadded_row_size, pixels_padded_row_size, |
+ false, buffer->address(), buffer_padded_row_size); |
+ } |
+ helper_->TexSubImage3D( |
+ target, level, xoffset, yoffset + row_index, zoffset + depth_index, |
+ width, my_height, my_depth, |
+ format, type, buffer->shm_id(), buffer->offset(), internal); |
+ buffer->Release(); |
+ |
+ total_rows -= num_rows; |
+ if (total_rows > 0) { |
+ GLint num_image_paddings; |
+ if (num_images > 0) { |
+ DCHECK_EQ(row_index, 0); |
+ depth_index += num_images; |
+ num_image_paddings = num_images; |
+ } else { |
+ row_index = (row_index + my_height) % height; |
+ num_image_paddings = 0; |
+ if (my_height > 0 && row_index == 0) { |
+ depth_index++; |
+ num_image_paddings++; |
+ } |
+ } |
+ source += num_rows * pixels_padded_row_size; |
+ if (unpack_image_height_ > height && num_image_paddings > 0) { |
+ source += num_image_paddings * (unpack_image_height_ - height) * |
+ pixels_padded_row_size; |
+ } |
+ } |
+ } |
+} |
+ |
bool GLES2Implementation::GetActiveAttribHelper( |
GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, |
GLenum* type, char* name) { |
@@ -2187,8 +2515,8 @@ void GLES2Implementation::ReadPixels( |
uint32 unpadded_row_size; |
uint32 padded_row_size; |
if (!GLES2Util::ComputeImageDataSizes( |
- width, 2, format, type, pack_alignment_, &temp_size, &unpadded_row_size, |
- &padded_row_size)) { |
+ width, 2, 1, format, type, pack_alignment_, &temp_size, |
+ &unpadded_row_size, &padded_row_size)) { |
SetGLError(GL_INVALID_VALUE, "glReadPixels", "size too large."); |
return; |
} |
@@ -2215,13 +2543,13 @@ void GLES2Implementation::ReadPixels( |
// Transfer by rows. |
// The max rows we can transfer. |
while (height) { |
- GLsizei desired_size = padded_row_size * height - 1 + unpadded_row_size; |
+ GLsizei desired_size = padded_row_size * (height - 1) + unpadded_row_size; |
ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_); |
if (!buffer.valid()) { |
return; |
} |
GLint num_rows = ComputeNumRowsThatFitInBuffer( |
- padded_row_size, unpadded_row_size, buffer.size()); |
+ padded_row_size, unpadded_row_size, buffer.size(), height); |
num_rows = std::min(num_rows, height); |
// NOTE: We must look up the address of the result area AFTER allocation |
// of the transfer buffer since the transfer buffer may be reallocated. |
@@ -2986,7 +3314,7 @@ void* GLES2Implementation::MapTexSubImage2DCHROMIUM( |
} |
uint32 size; |
if (!GLES2Util::ComputeImageDataSizes( |
- width, height, format, type, unpack_alignment_, &size, NULL, NULL)) { |
+ width, height, 1, format, type, unpack_alignment_, &size, NULL, NULL)) { |
SetGLError( |
GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "image size too large"); |
return NULL; |
@@ -3530,34 +3858,24 @@ void GLES2Implementation::TraceBeginCHROMIUM( |
GPU_CLIENT_SINGLE_THREAD_CHECK(); |
GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM(" |
<< category_name << ", " << trace_name << ")"); |
- if (current_trace_category_.get() || current_trace_name_.get()) { |
- SetGLError(GL_INVALID_OPERATION, "glTraceBeginCHROMIUM", |
- "trace already running"); |
- return; |
- } |
- TRACE_EVENT_COPY_ASYNC_BEGIN0(category_name, trace_name, this); |
SetBucketAsCString(kResultBucketId, category_name); |
- SetBucketAsCString(kResultBucketId + 1, category_name); |
+ SetBucketAsCString(kResultBucketId + 1, trace_name); |
helper_->TraceBeginCHROMIUM(kResultBucketId, kResultBucketId + 1); |
helper_->SetBucketSize(kResultBucketId, 0); |
helper_->SetBucketSize(kResultBucketId + 1, 0); |
- current_trace_category_.reset(new std::string(category_name)); |
- current_trace_name_.reset(new std::string(trace_name)); |
+ current_trace_stack_++; |
} |
void GLES2Implementation::TraceEndCHROMIUM() { |
GPU_CLIENT_SINGLE_THREAD_CHECK(); |
GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")"); |
- if (!current_trace_category_.get() || !current_trace_name_.get()) { |
+ if (current_trace_stack_ == 0) { |
SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM", |
"missing begin trace"); |
return; |
} |
helper_->TraceEndCHROMIUM(); |
- TRACE_EVENT_COPY_ASYNC_END0(current_trace_category_->c_str(), |
- current_trace_name_->c_str(), this); |
- current_trace_category_.reset(); |
- current_trace_name_.reset(); |
+ current_trace_stack_--; |
} |
void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) { |
@@ -3727,7 +4045,7 @@ void GLES2Implementation::AsyncTexImage2DCHROMIUM( |
uint32 unpadded_row_size; |
uint32 padded_row_size; |
if (!GLES2Util::ComputeImageDataSizes( |
- width, height, format, type, unpack_alignment_, &size, |
+ width, height, 1, format, type, unpack_alignment_, &size, |
&unpadded_row_size, &padded_row_size)) { |
SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large"); |
return; |
@@ -3787,7 +4105,7 @@ void GLES2Implementation::AsyncTexSubImage2DCHROMIUM( |
uint32 unpadded_row_size; |
uint32 padded_row_size; |
if (!GLES2Util::ComputeImageDataSizes( |
- width, height, format, type, unpack_alignment_, &size, |
+ width, height, 1, format, type, unpack_alignment_, &size, |
&unpadded_row_size, &padded_row_size)) { |
SetGLError( |
GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "size to large"); |