OLD | NEW |
1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // A class to emluate GLES2 over command buffers. | 5 // A class to emluate GLES2 over command buffers. |
6 | 6 |
7 #include "gpu/command_buffer/client/gles2_implementation.h" | 7 #include "gpu/command_buffer/client/gles2_implementation.h" |
8 // TODO(gman): remove when all functions have been implemented. | 8 // TODO(gman): remove when all functions have been implemented. |
9 #include "gpu/command_buffer/client/gles2_implementation_gen.h" | 9 #include "gpu/command_buffer/client/gles2_implementation_gen.h" |
10 #include "gpu/command_buffer/common/gles2_cmd_utils.h" | 10 #include "gpu/command_buffer/common/gles2_cmd_utils.h" |
11 | 11 |
12 namespace command_buffer { | 12 namespace command_buffer { |
13 namespace gles2 { | 13 namespace gles2 { |
14 | 14 |
15 GLES2Implementation::GLES2Implementation( | 15 GLES2Implementation::GLES2Implementation( |
16 GLES2CmdHelper* helper, | 16 GLES2CmdHelper* helper, |
| 17 size_t transfer_buffer_size, |
17 void* transfer_buffer, | 18 void* transfer_buffer, |
18 int transfer_buffer_id) | 19 int32 transfer_buffer_id) |
19 : util_(0), // TODO(gman): Get real number of compressed texture formats. | 20 : util_(0), // TODO(gman): Get real number of compressed texture formats. |
20 helper_(helper), | 21 helper_(helper), |
21 shared_memory_(transfer_buffer, transfer_buffer_id), | 22 transfer_buffer_(transfer_buffer_size, helper, transfer_buffer), |
| 23 transfer_buffer_id_(transfer_buffer_id), |
22 pack_alignment_(4), | 24 pack_alignment_(4), |
23 unpack_alignment_(4) { | 25 unpack_alignment_(4) { |
| 26 // Eat 1 id so we start at 1 instead of 0. |
| 27 GLuint eat; |
| 28 MakeIds(1, &eat); |
| 29 // Allocate space for simple GL results. |
| 30 result_buffer_ = transfer_buffer_.Alloc(kMaxSizeOfSimpleResult); |
| 31 result_shm_offset_ = transfer_buffer_.GetOffset(result_buffer_); |
24 } | 32 } |
25 | 33 |
26 void GLES2Implementation::MakeIds(GLsizei n, GLuint* ids) { | 34 void GLES2Implementation::MakeIds(GLsizei n, GLuint* ids) { |
27 for (GLsizei ii = 0; ii < n; ++ii) { | 35 for (GLsizei ii = 0; ii < n; ++ii) { |
28 ids[ii] = id_allocator_.AllocateID(); | 36 ids[ii] = id_allocator_.AllocateID(); |
29 } | 37 } |
30 } | 38 } |
31 | 39 |
32 void GLES2Implementation::FreeIds(GLsizei n, const GLuint* ids) { | 40 void GLES2Implementation::FreeIds(GLsizei n, const GLuint* ids) { |
33 for (GLsizei ii = 0; ii < n; ++ii) { | 41 for (GLsizei ii = 0; ii < n; ++ii) { |
34 id_allocator_.FreeID(ids[ii]); | 42 id_allocator_.FreeID(ids[ii]); |
35 } | 43 } |
36 } | 44 } |
37 | 45 |
| 46 void GLES2Implementation::WaitForCmd() { |
| 47 int32 token = helper_->InsertToken(); |
| 48 helper_->WaitForToken(token); |
| 49 } |
| 50 |
38 void GLES2Implementation::DrawElements( | 51 void GLES2Implementation::DrawElements( |
39 GLenum mode, GLsizei count, GLenum type, const void* indices) { | 52 GLenum mode, GLsizei count, GLenum type, const void* indices) { |
40 helper_->DrawElements(mode, count, type, reinterpret_cast<GLuint>(indices)); | 53 helper_->DrawElements(mode, count, type, reinterpret_cast<GLuint>(indices)); |
41 } | 54 } |
42 | 55 |
| 56 GLint GLES2Implementation::GetAttribLocation( |
| 57 GLuint program, const char* name) { |
| 58 helper_->GetAttribLocationImmediate( |
| 59 program, name, result_shm_id(), result_shm_offset()); |
| 60 WaitForCmd(); |
| 61 return GetResultAs<GLint>(); |
| 62 } |
| 63 |
| 64 GLint GLES2Implementation::GetUniformLocation( |
| 65 GLuint program, const char* name) { |
| 66 helper_->GetUniformLocationImmediate( |
| 67 program, name, result_shm_id(), result_shm_offset()); |
| 68 WaitForCmd(); |
| 69 return GetResultAs<GLint>(); |
| 70 } |
| 71 |
| 72 void GLES2Implementation::PixelStorei(GLenum pname, GLint param) { |
| 73 switch (pname) { |
| 74 case GL_PACK_ALIGNMENT: |
| 75 pack_alignment_ = param; |
| 76 break; |
| 77 case GL_UNPACK_ALIGNMENT: |
| 78 unpack_alignment_ = param; |
| 79 break; |
| 80 default: |
| 81 break; |
| 82 } |
| 83 helper_->PixelStorei(pname, param); |
| 84 } |
| 85 |
| 86 |
43 void GLES2Implementation::VertexAttribPointer( | 87 void GLES2Implementation::VertexAttribPointer( |
44 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, | 88 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, |
45 const void* ptr) { | 89 const void* ptr) { |
46 helper_->VertexAttribPointer(index, size, type, normalized, stride, | 90 helper_->VertexAttribPointer(index, size, type, normalized, stride, |
47 reinterpret_cast<GLuint>(ptr)); | 91 reinterpret_cast<GLuint>(ptr)); |
48 } | 92 } |
49 | 93 |
50 void GLES2Implementation::ShaderSource( | 94 void GLES2Implementation::ShaderSource( |
51 GLuint shader, GLsizei count, const char** string, const GLint* length) { | 95 GLuint shader, GLsizei count, const char** source, const GLint* length) { |
52 // TODO(gman): change to use buckets and check that there is enough room. | 96 // TODO(gman): change to use buckets and check that there is enough room. |
53 uint32* offsets = shared_memory_.GetAddressAs<uint32*>(0); | |
54 char* strings = reinterpret_cast<char*>(offsets + count); | |
55 | 97 |
| 98 // Compute the total size. |
| 99 uint32 total_size = count * sizeof(total_size); |
| 100 for (GLsizei ii = 0; ii < count; ++ii) { |
| 101 total_size += length ? length[ii] : strlen(source[ii]); |
| 102 } |
| 103 |
| 104 // Create string table in transfer buffer. |
| 105 char* strings = transfer_buffer_.AllocTyped<char>(total_size); |
| 106 uint32* offsets = reinterpret_cast<uint32*>(strings); |
56 uint32 offset = count * sizeof(*offsets); | 107 uint32 offset = count * sizeof(*offsets); |
57 for (GLsizei ii = 0; ii < count; ++ii) { | 108 for (GLsizei ii = 0; ii < count; ++ii) { |
58 uint32 len = length ? length[ii] : strlen(string[ii]); | 109 uint32 len = length ? length[ii] : strlen(source[ii]); |
59 memcpy(strings + offset, string[ii], len); | 110 memcpy(strings + offset, source[ii], len); |
60 offset += len; | 111 offset += len; |
61 offsets[ii] = offset; | 112 offsets[ii] = offset; |
62 } | 113 } |
63 | 114 |
64 helper_->ShaderSource(shader, count, shared_memory_.GetId(), 0, offset); | 115 helper_->ShaderSource(shader, count, |
65 // TODO(gman): Should insert token but not wait until we need shared memory | 116 transfer_buffer_id_, |
66 // again. Really, I should implement a shared memory manager that puts | 117 transfer_buffer_.GetOffset(strings), offset); |
67 // things in the next unused part of shared memory and only blocks | 118 transfer_buffer_.FreePendingToken(strings, helper_->InsertToken()); |
68 // when it needs more memory. | |
69 int32 token = helper_->InsertToken(); | |
70 helper_->WaitForToken(token); | |
71 } | 119 } |
72 | 120 |
73 void GLES2Implementation::BufferData( | 121 void GLES2Implementation::BufferData( |
74 GLenum target, GLsizeiptr size, const void* data, GLenum usage) { | 122 GLenum target, GLsizeiptr size, const void* data, GLenum usage) { |
75 // TODO(gman): Switch to use buckets alwayst or at least if no room in shared | 123 // NOTE: Should this be optimized for the case where we can call BufferData |
76 // memory. | 124 // with the actual data in the case of our transfer buffer being big |
77 memcpy(shared_memory_.GetAddress(0), data, size); | 125 // enough? |
78 helper_->BufferData(target, size, shared_memory_.GetId(), 0, usage); | 126 helper_->BufferData(target, size, 0, 0, usage); |
79 int32 token = helper_->InsertToken(); | 127 if (data != NULL) { |
80 helper_->WaitForToken(token); | 128 BufferSubData(target, 0, size, data); |
| 129 } |
81 } | 130 } |
82 | 131 |
83 void GLES2Implementation::BufferSubData( | 132 void GLES2Implementation::BufferSubData( |
84 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) { | 133 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) { |
85 // TODO(gman): Switch to use buckets alwayst or at least if no room in shared | 134 const int8* source = static_cast<const int8*>(data); |
86 // memory. | 135 GLsizeiptr max_size = transfer_buffer_.GetLargestFreeOrPendingSize(); |
87 memcpy(shared_memory_.GetAddress(0), data, size); | 136 while (size) { |
88 helper_->BufferSubData(target, offset, size, shared_memory_.GetId(), 0); | 137 GLsizeiptr part_size = std::min(size, max_size); |
89 int32 token = helper_->InsertToken(); | 138 void* buffer = transfer_buffer_.Alloc(part_size); |
90 helper_->WaitForToken(token); | 139 memcpy(buffer, source, part_size); |
| 140 helper_->BufferSubData(target, offset, part_size, |
| 141 transfer_buffer_id_, |
| 142 transfer_buffer_.GetOffset(buffer)); |
| 143 transfer_buffer_.FreePendingToken(buffer, helper_->InsertToken()); |
| 144 offset += part_size; |
| 145 source += part_size; |
| 146 size -= part_size; |
| 147 } |
91 } | 148 } |
92 | 149 |
93 void GLES2Implementation::CompressedTexImage2D( | 150 void GLES2Implementation::CompressedTexImage2D( |
94 GLenum target, GLint level, GLenum internalformat, GLsizei width, | 151 GLenum target, GLint level, GLenum internalformat, GLsizei width, |
95 GLsizei height, GLint border, GLsizei imageSize, const void* data) { | 152 GLsizei height, GLint border, GLsizei image_size, const void* data) { |
96 // TODO(gman): Switch to use buckets alwayst or at least if no room in shared | 153 // TODO(gman): Switch to use buckets alwayst or at least if no room in shared |
97 // memory. | 154 // memory. |
98 memcpy(shared_memory_.GetAddress(0), data, imageSize); | 155 DCHECK_LE(image_size, |
| 156 static_cast<GLsizei>( |
| 157 transfer_buffer_.GetLargestFreeOrPendingSize())); |
| 158 void* buffer = transfer_buffer_.Alloc(image_size); |
| 159 memcpy(buffer, data, image_size); |
99 helper_->CompressedTexImage2D( | 160 helper_->CompressedTexImage2D( |
100 target, level, internalformat, width, height, border, imageSize, | 161 target, level, internalformat, width, height, border, image_size, |
101 shared_memory_.GetId(), 0); | 162 transfer_buffer_id_, transfer_buffer_.GetOffset(buffer)); |
102 int32 token = helper_->InsertToken(); | 163 transfer_buffer_.FreePendingToken(buffer, helper_->InsertToken()); |
103 helper_->WaitForToken(token); | |
104 } | 164 } |
105 | 165 |
106 void GLES2Implementation::CompressedTexSubImage2D( | 166 void GLES2Implementation::CompressedTexSubImage2D( |
107 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, | 167 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, |
108 GLsizei height, GLenum format, GLsizei imageSize, const void* data) { | 168 GLsizei height, GLenum format, GLsizei image_size, const void* data) { |
109 // TODO(gman): Switch to use buckets alwayst or at least if no room in shared | 169 // TODO(gman): Switch to use buckets alwayst or at least if no room in shared |
110 // memory. | 170 // memory. |
111 memcpy(shared_memory_.GetAddress(0), data, imageSize); | 171 DCHECK_LE(image_size, |
| 172 static_cast<GLsizei>( |
| 173 transfer_buffer_.GetLargestFreeOrPendingSize())); |
| 174 void* buffer = transfer_buffer_.Alloc(image_size); |
| 175 memcpy(buffer, data, image_size); |
112 helper_->CompressedTexSubImage2D( | 176 helper_->CompressedTexSubImage2D( |
113 target, level, xoffset, yoffset, width, height, format, imageSize, | 177 target, level, xoffset, yoffset, width, height, format, image_size, |
114 shared_memory_.GetId(), 0); | 178 transfer_buffer_id_, transfer_buffer_.GetOffset(buffer)); |
115 int32 token = helper_->InsertToken(); | 179 transfer_buffer_.FreePendingToken(buffer, helper_->InsertToken()); |
116 helper_->WaitForToken(token); | |
117 } | 180 } |
118 | 181 |
119 void GLES2Implementation::TexImage2D( | 182 void GLES2Implementation::TexImage2D( |
120 GLenum target, GLint level, GLint internalformat, GLsizei width, | 183 GLenum target, GLint level, GLint internalformat, GLsizei width, |
121 GLsizei height, GLint border, GLenum format, GLenum type, | 184 GLsizei height, GLint border, GLenum format, GLenum type, |
122 const void* pixels) { | 185 const void* pixels) { |
123 // TODO(gman): Switch to use buckets alwayst or at least if no room in shared | |
124 // memory. | |
125 uint32 pixels_size = GLES2Util::ComputeImageDataSize( | |
126 width, height, format, type, unpack_alignment_); | |
127 memcpy(shared_memory_.GetAddress(0), pixels, pixels_size); | |
128 helper_->TexImage2D( | 186 helper_->TexImage2D( |
129 target, level, internalformat, width, height, border, format, type, | 187 target, level, internalformat, width, height, border, format, type, 0, 0); |
130 shared_memory_.GetId(), 0); | 188 if (pixels) { |
131 int32 token = helper_->InsertToken(); | 189 TexSubImage2D(target, level, 0, 0, width, height, format, type, pixels); |
132 helper_->WaitForToken(token); | 190 } |
133 } | 191 } |
134 | 192 |
135 void GLES2Implementation::TexSubImage2D( | 193 void GLES2Implementation::TexSubImage2D( |
136 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, | 194 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, |
137 GLsizei height, GLenum format, GLenum type, const void* pixels) { | 195 GLsizei height, GLenum format, GLenum type, const void* pixels) { |
138 // TODO(gman): Switch to use buckets alwayst or at least if no room in shared | 196 const int8* source = static_cast<const int8*>(pixels); |
139 // memory. | 197 GLsizeiptr max_size = transfer_buffer_.GetLargestFreeOrPendingSize(); |
140 uint32 pixels_size = GLES2Util::ComputeImageDataSize( | 198 |
141 width, height, format, type, unpack_alignment_); | 199 GLsizeiptr unpadded_row_size = GLES2Util::ComputeImageDataSize( |
142 memcpy(shared_memory_.GetAddress(0), pixels, pixels_size); | 200 width, 1, format, type, unpack_alignment_); |
143 helper_->TexSubImage2D( | 201 GLsizeiptr padded_row_size = GLES2Util::ComputeImageDataSize( |
144 target, level, xoffset, yoffset, width, height, format, type, | 202 width, 2, format, type, unpack_alignment_) - unpadded_row_size; |
145 shared_memory_.GetId(), 0); | 203 |
146 int32 token = helper_->InsertToken(); | 204 if (padded_row_size <= max_size) { |
147 helper_->WaitForToken(token); | 205 // Transfer by rows. |
| 206 GLint max_rows = max_size / padded_row_size; |
| 207 while (height) { |
| 208 GLint num_rows = std::min(height, max_rows); |
| 209 GLsizeiptr part_size = num_rows * padded_row_size; |
| 210 void* buffer = transfer_buffer_.Alloc(part_size); |
| 211 memcpy(buffer, source, part_size); |
| 212 helper_->TexSubImage2D( |
| 213 target, level, xoffset, yoffset, width, num_rows, format, type, |
| 214 transfer_buffer_id_, transfer_buffer_.GetOffset(buffer)); |
| 215 transfer_buffer_.FreePendingToken(buffer, helper_->InsertToken()); |
| 216 yoffset += num_rows; |
| 217 source += part_size; |
| 218 height -= num_rows; |
| 219 } |
| 220 } else { |
| 221 // Transfer by sub rows. Beacuse GL has no maximum texture dimensions. |
| 222 GLsizeiptr element_size = GLES2Util::ComputeImageDataSize( |
| 223 1, 1, format, type, unpack_alignment_); |
| 224 max_size -= max_size % element_size; |
| 225 GLint max_sub_row_pixels = max_size / element_size; |
| 226 for (; height; --height) { |
| 227 GLint temp_width = width; |
| 228 GLint temp_xoffset = xoffset; |
| 229 const int8* row_source = source; |
| 230 while (temp_width) { |
| 231 GLint num_pixels = std::min(width, max_sub_row_pixels); |
| 232 GLsizeiptr part_size = num_pixels * element_size; |
| 233 void* buffer = transfer_buffer_.Alloc(part_size); |
| 234 memcpy(buffer, row_source, part_size); |
| 235 helper_->TexSubImage2D( |
| 236 target, level, temp_xoffset, yoffset, temp_width, 1, format, type, |
| 237 transfer_buffer_id_, transfer_buffer_.GetOffset(buffer)); |
| 238 transfer_buffer_.FreePendingToken(buffer, helper_->InsertToken()); |
| 239 row_source += part_size; |
| 240 temp_xoffset += num_pixels; |
| 241 temp_width -= num_pixels; |
| 242 } |
| 243 ++yoffset; |
| 244 source += padded_row_size; |
| 245 } |
| 246 } |
148 } | 247 } |
149 | 248 |
150 | 249 |
151 } // namespace gles2 | 250 } // namespace gles2 |
152 } // namespace command_buffer | 251 } // namespace command_buffer |
153 | 252 |
154 | 253 |
OLD | NEW |