Index: gpu/command_buffer/client/gles2_implementation.cc |
=================================================================== |
--- gpu/command_buffer/client/gles2_implementation.cc (revision 33021) |
+++ gpu/command_buffer/client/gles2_implementation.cc (working copy) |
@@ -14,13 +14,21 @@ |
GLES2Implementation::GLES2Implementation( |
GLES2CmdHelper* helper, |
+ size_t transfer_buffer_size, |
void* transfer_buffer, |
- int transfer_buffer_id) |
+ int32 transfer_buffer_id) |
: util_(0), // TODO(gman): Get real number of compressed texture formats. |
helper_(helper), |
- shared_memory_(transfer_buffer, transfer_buffer_id), |
+ transfer_buffer_(transfer_buffer_size, helper, transfer_buffer), |
+ transfer_buffer_id_(transfer_buffer_id), |
pack_alignment_(4), |
unpack_alignment_(4) { |
+ // Eat 1 id so we start at 1 instead of 0. |
+ GLuint eat; |
+ MakeIds(1, &eat); |
+ // Allocate space for simple GL results. |
+ result_buffer_ = transfer_buffer_.Alloc(kMaxSizeOfSimpleResult); |
+ result_shm_offset_ = transfer_buffer_.GetOffset(result_buffer_); |
} |
void GLES2Implementation::MakeIds(GLsizei n, GLuint* ids) { |
@@ -35,11 +43,47 @@ |
} |
} |
+void GLES2Implementation::WaitForCmd() { |
+ int32 token = helper_->InsertToken(); |
+ helper_->WaitForToken(token); |
+} |
+ |
void GLES2Implementation::DrawElements( |
GLenum mode, GLsizei count, GLenum type, const void* indices) { |
helper_->DrawElements(mode, count, type, reinterpret_cast<GLuint>(indices)); |
} |
+GLint GLES2Implementation::GetAttribLocation( |
+ GLuint program, const char* name) { |
+ helper_->GetAttribLocationImmediate( |
+ program, name, result_shm_id(), result_shm_offset()); |
+ WaitForCmd(); |
+ return GetResultAs<GLint>(); |
+} |
+ |
+GLint GLES2Implementation::GetUniformLocation( |
+ GLuint program, const char* name) { |
+ helper_->GetUniformLocationImmediate( |
+ program, name, result_shm_id(), result_shm_offset()); |
+ WaitForCmd(); |
+ return GetResultAs<GLint>(); |
+} |
+ |
+void GLES2Implementation::PixelStorei(GLenum pname, GLint param) { |
+ switch (pname) { |
+ case GL_PACK_ALIGNMENT: |
+ pack_alignment_ = param; |
+ break; |
+ case GL_UNPACK_ALIGNMENT: |
+ unpack_alignment_ = param; |
+ break; |
+ default: |
+ break; |
+ } |
+ helper_->PixelStorei(pname, param); |
+} |
+ |
+ |
void GLES2Implementation::VertexAttribPointer( |
GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, |
const void* ptr) { |
@@ -48,103 +92,158 @@ |
} |
void GLES2Implementation::ShaderSource( |
- GLuint shader, GLsizei count, const char** string, const GLint* length) { |
+ GLuint shader, GLsizei count, const char** source, const GLint* length) { |
// TODO(gman): change to use buckets and check that there is enough room. |
- uint32* offsets = shared_memory_.GetAddressAs<uint32*>(0); |
- char* strings = reinterpret_cast<char*>(offsets + count); |
+ // Compute the total size. |
+ uint32 total_size = count * sizeof(total_size); |
+ for (GLsizei ii = 0; ii < count; ++ii) { |
+ total_size += length ? length[ii] : strlen(source[ii]); |
+ } |
+ |
+ // Create string table in transfer buffer. |
+ char* strings = transfer_buffer_.AllocTyped<char>(total_size); |
+ uint32* offsets = reinterpret_cast<uint32*>(strings); |
uint32 offset = count * sizeof(*offsets); |
for (GLsizei ii = 0; ii < count; ++ii) { |
- uint32 len = length ? length[ii] : strlen(string[ii]); |
- memcpy(strings + offset, string[ii], len); |
+ uint32 len = length ? length[ii] : strlen(source[ii]); |
+ memcpy(strings + offset, source[ii], len); |
offset += len; |
offsets[ii] = offset; |
} |
- helper_->ShaderSource(shader, count, shared_memory_.GetId(), 0, offset); |
- // TODO(gman): Should insert token but not wait until we need shared memory |
- // again. Really, I should implement a shared memory manager that puts |
- // things in the next unused part of shared memory and only blocks |
- // when it needs more memory. |
- int32 token = helper_->InsertToken(); |
- helper_->WaitForToken(token); |
+ helper_->ShaderSource(shader, count, |
+ transfer_buffer_id_, |
+ transfer_buffer_.GetOffset(strings), offset); |
+ transfer_buffer_.FreePendingToken(strings, helper_->InsertToken()); |
} |
void GLES2Implementation::BufferData( |
GLenum target, GLsizeiptr size, const void* data, GLenum usage) { |
- // TODO(gman): Switch to use buckets alwayst or at least if no room in shared |
- // memory. |
- memcpy(shared_memory_.GetAddress(0), data, size); |
- helper_->BufferData(target, size, shared_memory_.GetId(), 0, usage); |
- int32 token = helper_->InsertToken(); |
- helper_->WaitForToken(token); |
+ // NOTE: Should this be optimized for the case where we can call BufferData |
+ // with the actual data in the case of our transfer buffer being big |
+ // enough? |
+ helper_->BufferData(target, size, 0, 0, usage); |
+ if (data != NULL) { |
+ BufferSubData(target, 0, size, data); |
+ } |
} |
void GLES2Implementation::BufferSubData( |
GLenum target, GLintptr offset, GLsizeiptr size, const void* data) { |
- // TODO(gman): Switch to use buckets alwayst or at least if no room in shared |
- // memory. |
- memcpy(shared_memory_.GetAddress(0), data, size); |
- helper_->BufferSubData(target, offset, size, shared_memory_.GetId(), 0); |
- int32 token = helper_->InsertToken(); |
- helper_->WaitForToken(token); |
+ const int8* source = static_cast<const int8*>(data); |
+ GLsizeiptr max_size = transfer_buffer_.GetLargestFreeOrPendingSize(); |
+ while (size) { |
+ GLsizeiptr part_size = std::min(size, max_size); |
+ void* buffer = transfer_buffer_.Alloc(part_size); |
+ memcpy(buffer, source, part_size); |
+ helper_->BufferSubData(target, offset, part_size, |
+ transfer_buffer_id_, |
+ transfer_buffer_.GetOffset(buffer)); |
+ transfer_buffer_.FreePendingToken(buffer, helper_->InsertToken()); |
+ offset += part_size; |
+ source += part_size; |
+ size -= part_size; |
+ } |
} |
void GLES2Implementation::CompressedTexImage2D( |
GLenum target, GLint level, GLenum internalformat, GLsizei width, |
- GLsizei height, GLint border, GLsizei imageSize, const void* data) { |
+ GLsizei height, GLint border, GLsizei image_size, const void* data) { |
// TODO(gman): Switch to use buckets alwayst or at least if no room in shared |
// memory. |
- memcpy(shared_memory_.GetAddress(0), data, imageSize); |
+ DCHECK_LE(image_size, |
+ static_cast<GLsizei>( |
+ transfer_buffer_.GetLargestFreeOrPendingSize())); |
+ void* buffer = transfer_buffer_.Alloc(image_size); |
+ memcpy(buffer, data, image_size); |
helper_->CompressedTexImage2D( |
- target, level, internalformat, width, height, border, imageSize, |
- shared_memory_.GetId(), 0); |
- int32 token = helper_->InsertToken(); |
- helper_->WaitForToken(token); |
+ target, level, internalformat, width, height, border, image_size, |
+ transfer_buffer_id_, transfer_buffer_.GetOffset(buffer)); |
+ transfer_buffer_.FreePendingToken(buffer, helper_->InsertToken()); |
} |
void GLES2Implementation::CompressedTexSubImage2D( |
GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, |
- GLsizei height, GLenum format, GLsizei imageSize, const void* data) { |
+ GLsizei height, GLenum format, GLsizei image_size, const void* data) { |
// TODO(gman): Switch to use buckets alwayst or at least if no room in shared |
// memory. |
- memcpy(shared_memory_.GetAddress(0), data, imageSize); |
+ DCHECK_LE(image_size, |
+ static_cast<GLsizei>( |
+ transfer_buffer_.GetLargestFreeOrPendingSize())); |
+ void* buffer = transfer_buffer_.Alloc(image_size); |
+ memcpy(buffer, data, image_size); |
helper_->CompressedTexSubImage2D( |
- target, level, xoffset, yoffset, width, height, format, imageSize, |
- shared_memory_.GetId(), 0); |
- int32 token = helper_->InsertToken(); |
- helper_->WaitForToken(token); |
+ target, level, xoffset, yoffset, width, height, format, image_size, |
+ transfer_buffer_id_, transfer_buffer_.GetOffset(buffer)); |
+ transfer_buffer_.FreePendingToken(buffer, helper_->InsertToken()); |
} |
void GLES2Implementation::TexImage2D( |
GLenum target, GLint level, GLint internalformat, GLsizei width, |
GLsizei height, GLint border, GLenum format, GLenum type, |
const void* pixels) { |
- // TODO(gman): Switch to use buckets alwayst or at least if no room in shared |
- // memory. |
- uint32 pixels_size = GLES2Util::ComputeImageDataSize( |
- width, height, format, type, unpack_alignment_); |
- memcpy(shared_memory_.GetAddress(0), pixels, pixels_size); |
helper_->TexImage2D( |
- target, level, internalformat, width, height, border, format, type, |
- shared_memory_.GetId(), 0); |
- int32 token = helper_->InsertToken(); |
- helper_->WaitForToken(token); |
+ target, level, internalformat, width, height, border, format, type, 0, 0); |
+ if (pixels) { |
+ TexSubImage2D(target, level, 0, 0, width, height, format, type, pixels); |
+ } |
} |
void GLES2Implementation::TexSubImage2D( |
GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, |
GLsizei height, GLenum format, GLenum type, const void* pixels) { |
- // TODO(gman): Switch to use buckets alwayst or at least if no room in shared |
- // memory. |
- uint32 pixels_size = GLES2Util::ComputeImageDataSize( |
- width, height, format, type, unpack_alignment_); |
- memcpy(shared_memory_.GetAddress(0), pixels, pixels_size); |
- helper_->TexSubImage2D( |
- target, level, xoffset, yoffset, width, height, format, type, |
- shared_memory_.GetId(), 0); |
- int32 token = helper_->InsertToken(); |
- helper_->WaitForToken(token); |
+ const int8* source = static_cast<const int8*>(pixels); |
+ GLsizeiptr max_size = transfer_buffer_.GetLargestFreeOrPendingSize(); |
+ |
+ GLsizeiptr unpadded_row_size = GLES2Util::ComputeImageDataSize( |
+ width, 1, format, type, unpack_alignment_); |
+ GLsizeiptr padded_row_size = GLES2Util::ComputeImageDataSize( |
+ width, 2, format, type, unpack_alignment_) - unpadded_row_size; |
+ |
+ if (padded_row_size <= max_size) { |
+ // Transfer by rows. |
+ GLint max_rows = max_size / padded_row_size; |
+ while (height) { |
+ GLint num_rows = std::min(height, max_rows); |
+ GLsizeiptr part_size = num_rows * padded_row_size; |
+ void* buffer = transfer_buffer_.Alloc(part_size); |
+ memcpy(buffer, source, part_size); |
+ helper_->TexSubImage2D( |
+ target, level, xoffset, yoffset, width, num_rows, format, type, |
+ transfer_buffer_id_, transfer_buffer_.GetOffset(buffer)); |
+ transfer_buffer_.FreePendingToken(buffer, helper_->InsertToken()); |
+ yoffset += num_rows; |
+ source += part_size; |
+ height -= num_rows; |
+ } |
+ } else { |
+ // Transfer by sub rows. Beacuse GL has no maximum texture dimensions. |
+ GLsizeiptr element_size = GLES2Util::ComputeImageDataSize( |
+ 1, 1, format, type, unpack_alignment_); |
+ max_size -= max_size % element_size; |
+ GLint max_sub_row_pixels = max_size / element_size; |
+ for (; height; --height) { |
+ GLint temp_width = width; |
+ GLint temp_xoffset = xoffset; |
+ const int8* row_source = source; |
+ while (temp_width) { |
+ GLint num_pixels = std::min(width, max_sub_row_pixels); |
+ GLsizeiptr part_size = num_pixels * element_size; |
+ void* buffer = transfer_buffer_.Alloc(part_size); |
+ memcpy(buffer, row_source, part_size); |
+ helper_->TexSubImage2D( |
+ target, level, temp_xoffset, yoffset, temp_width, 1, format, type, |
+ transfer_buffer_id_, transfer_buffer_.GetOffset(buffer)); |
+ transfer_buffer_.FreePendingToken(buffer, helper_->InsertToken()); |
+ row_source += part_size; |
+ temp_xoffset += num_pixels; |
+ temp_width -= num_pixels; |
+ } |
+ ++yoffset; |
+ source += padded_row_size; |
+ } |
+ } |
} |