OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 #include "ui/gl/gl_image_memory.h" | 5 #include "ui/gl/gl_image_memory.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/numerics/safe_conversions.h" |
8 #include "base/trace_event/trace_event.h" | 9 #include "base/trace_event/trace_event.h" |
9 #include "ui/gfx/buffer_format_util.h" | 10 #include "ui/gfx/buffer_format_util.h" |
10 #include "ui/gl/gl_bindings.h" | 11 #include "ui/gl/gl_bindings.h" |
11 #include "ui/gl/gl_context.h" | 12 #include "ui/gl/gl_context.h" |
12 #include "ui/gl/gl_version_info.h" | 13 #include "ui/gl/gl_version_info.h" |
13 | 14 |
14 using gfx::BufferFormat; | 15 using gfx::BufferFormat; |
15 | 16 |
16 namespace gl { | 17 namespace gl { |
17 namespace { | 18 namespace { |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
64 case BufferFormat::DXT1: | 65 case BufferFormat::DXT1: |
65 case BufferFormat::DXT5: | 66 case BufferFormat::DXT5: |
66 case BufferFormat::ETC1: | 67 case BufferFormat::ETC1: |
67 return true; | 68 return true; |
68 case BufferFormat::R_8: | 69 case BufferFormat::R_8: |
69 case BufferFormat::RGBA_4444: | 70 case BufferFormat::RGBA_4444: |
70 case BufferFormat::RGBX_8888: | 71 case BufferFormat::RGBX_8888: |
71 case BufferFormat::RGBA_8888: | 72 case BufferFormat::RGBA_8888: |
72 case BufferFormat::BGRX_8888: | 73 case BufferFormat::BGRX_8888: |
73 case BufferFormat::BGRA_8888: | 74 case BufferFormat::BGRA_8888: |
| 75 return false; |
74 case BufferFormat::YUV_420: | 76 case BufferFormat::YUV_420: |
75 case BufferFormat::YUV_420_BIPLANAR: | 77 case BufferFormat::YUV_420_BIPLANAR: |
76 case BufferFormat::UYVY_422: | 78 case BufferFormat::UYVY_422: |
| 79 NOTREACHED(); |
77 return false; | 80 return false; |
78 } | 81 } |
79 | 82 |
80 NOTREACHED(); | 83 NOTREACHED(); |
81 return false; | 84 return false; |
82 } | 85 } |
83 | 86 |
84 GLenum TextureFormat(BufferFormat format) { | 87 GLenum TextureFormat(BufferFormat format) { |
85 switch (format) { | 88 switch (format) { |
86 case BufferFormat::ATC: | 89 case BufferFormat::ATC: |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 return GL_BGRA_EXT; | 125 return GL_BGRA_EXT; |
123 case BufferFormat::RGBA_4444: | 126 case BufferFormat::RGBA_4444: |
124 case BufferFormat::RGBA_8888: | 127 case BufferFormat::RGBA_8888: |
125 case BufferFormat::BGRA_8888: | 128 case BufferFormat::BGRA_8888: |
126 case BufferFormat::R_8: | 129 case BufferFormat::R_8: |
127 case BufferFormat::ATC: | 130 case BufferFormat::ATC: |
128 case BufferFormat::ATCIA: | 131 case BufferFormat::ATCIA: |
129 case BufferFormat::DXT1: | 132 case BufferFormat::DXT1: |
130 case BufferFormat::DXT5: | 133 case BufferFormat::DXT5: |
131 case BufferFormat::ETC1: | 134 case BufferFormat::ETC1: |
| 135 return TextureFormat(format); |
132 case BufferFormat::YUV_420: | 136 case BufferFormat::YUV_420: |
133 case BufferFormat::YUV_420_BIPLANAR: | 137 case BufferFormat::YUV_420_BIPLANAR: |
134 case BufferFormat::UYVY_422: | 138 case BufferFormat::UYVY_422: |
135 return TextureFormat(format); | 139 NOTREACHED(); |
| 140 return 0; |
136 } | 141 } |
137 | 142 |
138 NOTREACHED(); | 143 NOTREACHED(); |
139 return 0; | 144 return 0; |
140 } | 145 } |
141 | 146 |
142 GLenum DataType(BufferFormat format) { | 147 GLenum DataType(BufferFormat format) { |
143 switch (format) { | 148 switch (format) { |
144 case BufferFormat::RGBA_4444: | 149 case BufferFormat::RGBA_4444: |
145 return GL_UNSIGNED_SHORT_4_4_4_4; | 150 return GL_UNSIGNED_SHORT_4_4_4_4; |
(...skipping 12 matching lines...) Expand all Loading... |
158 case BufferFormat::YUV_420_BIPLANAR: | 163 case BufferFormat::YUV_420_BIPLANAR: |
159 case BufferFormat::UYVY_422: | 164 case BufferFormat::UYVY_422: |
160 NOTREACHED(); | 165 NOTREACHED(); |
161 return 0; | 166 return 0; |
162 } | 167 } |
163 | 168 |
164 NOTREACHED(); | 169 NOTREACHED(); |
165 return 0; | 170 return 0; |
166 } | 171 } |
167 | 172 |
| 173 GLint DataRowLength(size_t stride, BufferFormat format) { |
| 174 switch (format) { |
| 175 case BufferFormat::RGBA_4444: |
| 176 return base::checked_cast<GLint>(stride) / 2; |
| 177 case BufferFormat::RGBX_8888: |
| 178 case BufferFormat::RGBA_8888: |
| 179 case BufferFormat::BGRX_8888: |
| 180 case BufferFormat::BGRA_8888: |
| 181 return base::checked_cast<GLint>(stride) / 4; |
| 182 case BufferFormat::R_8: |
| 183 return base::checked_cast<GLint>(stride); |
| 184 case BufferFormat::ATC: |
| 185 case BufferFormat::ATCIA: |
| 186 case BufferFormat::DXT1: |
| 187 case BufferFormat::DXT5: |
| 188 case BufferFormat::ETC1: |
| 189 case BufferFormat::YUV_420: |
| 190 case BufferFormat::YUV_420_BIPLANAR: |
| 191 case BufferFormat::UYVY_422: |
| 192 NOTREACHED(); |
| 193 return 0; |
| 194 } |
| 195 |
| 196 NOTREACHED(); |
| 197 return 0; |
| 198 } |
| 199 |
168 template <typename F> | 200 template <typename F> |
169 scoped_ptr<uint8_t[]> GLES2RGBData(const gfx::Size& size, | 201 scoped_ptr<uint8_t[]> GLES2RGBData(const gfx::Size& size, |
170 BufferFormat format, | 202 BufferFormat format, |
| 203 size_t stride, |
171 const uint8_t* data, | 204 const uint8_t* data, |
172 F const& data_to_rgb, | 205 F const& data_to_rgb, |
173 GLenum* data_format, | 206 GLenum* data_format, |
174 GLenum* data_type) { | 207 GLenum* data_type, |
| 208 GLint* data_row_length) { |
175 TRACE_EVENT2("gpu", "GLES2RGBData", "width", size.width(), "height", | 209 TRACE_EVENT2("gpu", "GLES2RGBData", "width", size.width(), "height", |
176 size.height()); | 210 size.height()); |
177 | 211 |
178 // Four-byte row alignment as specified by glPixelStorei with argument | 212 // Four-byte row alignment as specified by glPixelStorei with argument |
179 // GL_UNPACK_ALIGNMENT set to 4. | 213 // GL_UNPACK_ALIGNMENT set to 4. |
180 size_t gles2_rgb_data_stride = (size.width() * 3 + 3) & ~3; | 214 size_t gles2_rgb_data_stride = (size.width() * 3 + 3) & ~3; |
181 scoped_ptr<uint8_t[]> gles2_rgb_data( | 215 scoped_ptr<uint8_t[]> gles2_rgb_data( |
182 new uint8_t[gles2_rgb_data_stride * size.height()]); | 216 new uint8_t[gles2_rgb_data_stride * size.height()]); |
183 size_t data_stride = RowSizeForBufferFormat(size.width(), format, 0); | |
184 | 217 |
185 for (int y = 0; y < size.height(); ++y) { | 218 for (int y = 0; y < size.height(); ++y) { |
186 for (int x = 0; x < size.width(); ++x) { | 219 for (int x = 0; x < size.width(); ++x) { |
187 data_to_rgb(&data[y * data_stride + x * 4], | 220 data_to_rgb(&data[y * stride + x * 4], |
188 &gles2_rgb_data[y * gles2_rgb_data_stride + x * 3]); | 221 &gles2_rgb_data[y * gles2_rgb_data_stride + x * 3]); |
189 } | 222 } |
190 } | 223 } |
191 | 224 |
192 *data_format = GL_RGB; | 225 *data_format = GL_RGB; |
193 *data_type = GL_UNSIGNED_BYTE; | 226 *data_type = GL_UNSIGNED_BYTE; |
| 227 *data_row_length = size.width(); |
194 return gles2_rgb_data.Pass(); | 228 return gles2_rgb_data.Pass(); |
195 } | 229 } |
196 | 230 |
197 scoped_ptr<uint8_t[]> GLES2Data(const gfx::Size& size, | 231 scoped_ptr<uint8_t[]> GLES2Data(const gfx::Size& size, |
198 BufferFormat format, | 232 BufferFormat format, |
| 233 size_t stride, |
199 const uint8_t* data, | 234 const uint8_t* data, |
200 GLenum* data_format, | 235 GLenum* data_format, |
201 GLenum* data_type) { | 236 GLenum* data_type, |
| 237 GLint* data_row_length) { |
| 238 TRACE_EVENT2("gpu", "GLES2Data", "width", size.width(), "height", |
| 239 size.height()); |
| 240 |
202 switch (format) { | 241 switch (format) { |
203 case BufferFormat::RGBX_8888: | 242 case BufferFormat::RGBX_8888: |
204 return GLES2RGBData(size, format, | 243 return GLES2RGBData(size, format, stride, |
205 data, [](const uint8_t* src, uint8_t* dst) { | 244 data, [](const uint8_t* src, uint8_t* dst) { |
206 dst[0] = src[0]; | 245 dst[0] = src[0]; |
207 dst[1] = src[1]; | 246 dst[1] = src[1]; |
208 dst[2] = src[2]; | 247 dst[2] = src[2]; |
209 }, data_format, data_type); | 248 }, data_format, data_type, data_row_length); |
210 case BufferFormat::BGRX_8888: | 249 case BufferFormat::BGRX_8888: |
211 return GLES2RGBData(size, format, | 250 return GLES2RGBData(size, format, stride, |
212 data, [](const uint8_t* src, uint8_t* dst) { | 251 data, [](const uint8_t* src, uint8_t* dst) { |
213 dst[0] = src[2]; | 252 dst[0] = src[2]; |
214 dst[1] = src[1]; | 253 dst[1] = src[1]; |
215 dst[2] = src[0]; | 254 dst[2] = src[0]; |
216 }, data_format, data_type); | 255 }, data_format, data_type, data_row_length); |
217 case BufferFormat::RGBA_4444: | 256 case BufferFormat::RGBA_4444: |
218 case BufferFormat::RGBA_8888: | 257 case BufferFormat::RGBA_8888: |
219 case BufferFormat::BGRA_8888: | 258 case BufferFormat::BGRA_8888: |
220 case BufferFormat::R_8: | 259 case BufferFormat::R_8: { |
| 260 size_t gles2_data_stride = |
| 261 RowSizeForBufferFormat(size.width(), format, 0); |
| 262 if (stride == gles2_data_stride) |
| 263 return nullptr; // No data conversion needed |
| 264 |
| 265 scoped_ptr<uint8_t[]> gles2_data( |
| 266 new uint8_t[gles2_data_stride * size.height()]); |
| 267 for (int y = 0; y < size.height(); ++y) { |
| 268 memcpy(&gles2_data[y * gles2_data_stride], &data[y * stride], |
| 269 gles2_data_stride); |
| 270 } |
| 271 *data_row_length = size.width(); |
| 272 return gles2_data.Pass(); |
| 273 } |
221 case BufferFormat::ATC: | 274 case BufferFormat::ATC: |
222 case BufferFormat::ATCIA: | 275 case BufferFormat::ATCIA: |
223 case BufferFormat::DXT1: | 276 case BufferFormat::DXT1: |
224 case BufferFormat::DXT5: | 277 case BufferFormat::DXT5: |
225 case BufferFormat::ETC1: | 278 case BufferFormat::ETC1: |
| 279 return nullptr; // No data conversion needed |
226 case BufferFormat::YUV_420: | 280 case BufferFormat::YUV_420: |
227 case BufferFormat::YUV_420_BIPLANAR: | 281 case BufferFormat::YUV_420_BIPLANAR: |
228 case BufferFormat::UYVY_422: | 282 case BufferFormat::UYVY_422: |
229 // No data conversion needed. | 283 NOTREACHED(); |
230 return nullptr; | 284 return nullptr; |
231 } | 285 } |
232 | 286 |
233 NOTREACHED(); | 287 NOTREACHED(); |
234 return 0; | 288 return nullptr; |
235 } | 289 } |
236 | 290 |
237 } // namespace | 291 } // namespace |
238 | 292 |
239 GLImageMemory::GLImageMemory(const gfx::Size& size, unsigned internalformat) | 293 GLImageMemory::GLImageMemory(const gfx::Size& size, unsigned internalformat) |
240 : size_(size), | 294 : size_(size), |
241 internalformat_(internalformat), | 295 internalformat_(internalformat), |
242 memory_(nullptr), | 296 memory_(nullptr), |
243 format_(BufferFormat::RGBA_8888) {} | 297 format_(BufferFormat::RGBA_8888), |
| 298 stride_(0) {} |
244 | 299 |
245 GLImageMemory::~GLImageMemory() { | 300 GLImageMemory::~GLImageMemory() { |
246 DCHECK(!memory_); | 301 DCHECK(!memory_); |
247 } | 302 } |
248 | 303 |
249 bool GLImageMemory::Initialize(const unsigned char* memory, | 304 bool GLImageMemory::Initialize(const unsigned char* memory, |
250 BufferFormat format) { | 305 BufferFormat format, |
| 306 size_t stride) { |
251 if (!ValidInternalFormat(internalformat_)) { | 307 if (!ValidInternalFormat(internalformat_)) { |
252 LOG(ERROR) << "Invalid internalformat: " << internalformat_; | 308 LOG(ERROR) << "Invalid internalformat: " << internalformat_; |
253 return false; | 309 return false; |
254 } | 310 } |
255 | 311 |
256 if (!ValidFormat(format)) { | 312 if (!ValidFormat(format)) { |
257 LOG(ERROR) << "Invalid format: " << static_cast<int>(format); | 313 LOG(ERROR) << "Invalid format: " << static_cast<int>(format); |
258 return false; | 314 return false; |
259 } | 315 } |
260 | 316 |
| 317 if (stride < RowSizeForBufferFormat(size_.width(), format, 0) || stride & 3) { |
| 318 LOG(ERROR) << "Invalid stride: " << stride; |
| 319 return false; |
| 320 } |
| 321 |
261 DCHECK(memory); | 322 DCHECK(memory); |
262 DCHECK(!memory_); | 323 DCHECK(!memory_); |
263 DCHECK(!IsCompressedFormat(format) || size_.width() % 4 == 0); | 324 DCHECK(!IsCompressedFormat(format) || size_.width() % 4 == 0); |
264 DCHECK(!IsCompressedFormat(format) || size_.height() % 4 == 0); | 325 DCHECK(!IsCompressedFormat(format) || size_.height() % 4 == 0); |
265 memory_ = memory; | 326 memory_ = memory; |
266 format_ = format; | 327 format_ = format; |
| 328 stride_ = stride; |
267 return true; | 329 return true; |
268 } | 330 } |
269 | 331 |
270 void GLImageMemory::Destroy(bool have_context) { | 332 void GLImageMemory::Destroy(bool have_context) { |
271 memory_ = nullptr; | 333 memory_ = nullptr; |
272 } | 334 } |
273 | 335 |
274 gfx::Size GLImageMemory::GetSize() { | 336 gfx::Size GLImageMemory::GetSize() { |
275 return size_; | 337 return size_; |
276 } | 338 } |
(...skipping 13 matching lines...) Expand all Loading... |
290 // GL_TEXTURE_EXTERNAL_OES is not a supported target. | 352 // GL_TEXTURE_EXTERNAL_OES is not a supported target. |
291 if (target == GL_TEXTURE_EXTERNAL_OES) | 353 if (target == GL_TEXTURE_EXTERNAL_OES) |
292 return false; | 354 return false; |
293 | 355 |
294 if (IsCompressedFormat(format_)) { | 356 if (IsCompressedFormat(format_)) { |
295 glCompressedTexImage2D( | 357 glCompressedTexImage2D( |
296 target, 0, TextureFormat(format_), size_.width(), size_.height(), 0, | 358 target, 0, TextureFormat(format_), size_.width(), size_.height(), 0, |
297 static_cast<GLsizei>(BufferSizeForBufferFormat(size_, format_)), | 359 static_cast<GLsizei>(BufferSizeForBufferFormat(size_, format_)), |
298 memory_); | 360 memory_); |
299 } else { | 361 } else { |
300 scoped_ptr<uint8_t[]> gles2_data; | |
301 GLenum data_format = DataFormat(format_); | 362 GLenum data_format = DataFormat(format_); |
302 GLenum data_type = DataType(format_); | 363 GLenum data_type = DataType(format_); |
| 364 GLint data_row_length = DataRowLength(stride_, format_); |
| 365 scoped_ptr<uint8_t[]> gles2_data; |
303 | 366 |
304 if (gfx::GLContext::GetCurrent()->GetVersionInfo()->is_es) | 367 if (gfx::GLContext::GetCurrent()->GetVersionInfo()->is_es) { |
305 gles2_data = GLES2Data(size_, format_, memory_, &data_format, &data_type); | 368 gles2_data = GLES2Data(size_, format_, stride_, memory_, &data_format, |
| 369 &data_type, &data_row_length); |
| 370 } |
| 371 |
| 372 if (data_row_length != size_.width()) |
| 373 glPixelStorei(GL_UNPACK_ROW_LENGTH, data_row_length); |
306 | 374 |
307 glTexImage2D(target, 0, TextureFormat(format_), size_.width(), | 375 glTexImage2D(target, 0, TextureFormat(format_), size_.width(), |
308 size_.height(), 0, data_format, data_type, | 376 size_.height(), 0, data_format, data_type, |
309 gles2_data ? gles2_data.get() : memory_); | 377 gles2_data ? gles2_data.get() : memory_); |
| 378 |
| 379 if (data_row_length != size_.width()) |
| 380 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); |
310 } | 381 } |
311 | 382 |
312 return true; | 383 return true; |
313 } | 384 } |
314 | 385 |
315 bool GLImageMemory::CopyTexSubImage(unsigned target, | 386 bool GLImageMemory::CopyTexSubImage(unsigned target, |
316 const gfx::Point& offset, | 387 const gfx::Point& offset, |
317 const gfx::Rect& rect) { | 388 const gfx::Rect& rect) { |
318 TRACE_EVENT2("gpu", "GLImageMemory::CopyTexSubImage", "width", rect.width(), | 389 TRACE_EVENT2("gpu", "GLImageMemory::CopyTexSubImage", "width", rect.width(), |
319 "height", rect.height()); | 390 "height", rect.height()); |
320 | 391 |
321 // GL_TEXTURE_EXTERNAL_OES is not a supported target. | 392 // GL_TEXTURE_EXTERNAL_OES is not a supported target. |
322 if (target == GL_TEXTURE_EXTERNAL_OES) | 393 if (target == GL_TEXTURE_EXTERNAL_OES) |
323 return false; | 394 return false; |
324 | 395 |
325 // Sub width is not supported. | 396 // Sub width is not supported. |
326 if (rect.width() != size_.width()) | 397 if (rect.width() != size_.width()) |
327 return false; | 398 return false; |
328 | 399 |
329 // Height must be a multiple of 4 if compressed. | 400 const uint8_t* data = memory_ + rect.y() * stride_; |
330 if (IsCompressedFormat(format_) && rect.height() % 4) | 401 if (IsCompressedFormat(format_)) { |
331 return false; | 402 // Height must be a multiple of 4. |
| 403 if (rect.height() % 4) |
| 404 return false; |
332 | 405 |
333 const uint8_t* data = | |
334 memory_ + rect.y() * RowSizeForBufferFormat(size_.width(), format_, 0); | |
335 if (IsCompressedFormat(format_)) { | |
336 glCompressedTexSubImage2D( | 406 glCompressedTexSubImage2D( |
337 target, 0, offset.x(), offset.y(), rect.width(), rect.height(), | 407 target, 0, offset.x(), offset.y(), rect.width(), rect.height(), |
338 DataFormat(format_), | 408 DataFormat(format_), |
339 static_cast<GLsizei>(BufferSizeForBufferFormat(rect.size(), format_)), | 409 static_cast<GLsizei>(BufferSizeForBufferFormat(rect.size(), format_)), |
340 data); | 410 data); |
341 } else { | 411 } else { |
342 GLenum data_format = DataFormat(format_); | 412 GLenum data_format = DataFormat(format_); |
343 GLenum data_type = DataType(format_); | 413 GLenum data_type = DataType(format_); |
| 414 GLint data_row_length = DataRowLength(stride_, format_); |
344 scoped_ptr<uint8_t[]> gles2_data; | 415 scoped_ptr<uint8_t[]> gles2_data; |
345 | 416 |
346 if (gfx::GLContext::GetCurrent()->GetVersionInfo()->is_es) { | 417 if (gfx::GLContext::GetCurrent()->GetVersionInfo()->is_es) { |
347 gles2_data = | 418 gles2_data = GLES2Data(rect.size(), format_, stride_, data, &data_format, |
348 GLES2Data(rect.size(), format_, data, &data_format, &data_type); | 419 &data_type, &data_row_length); |
349 } | 420 } |
350 | 421 |
| 422 if (data_row_length != rect.width()) |
| 423 glPixelStorei(GL_UNPACK_ROW_LENGTH, data_row_length); |
| 424 |
351 glTexSubImage2D(target, 0, offset.x(), offset.y(), rect.width(), | 425 glTexSubImage2D(target, 0, offset.x(), offset.y(), rect.width(), |
352 rect.height(), data_format, data_type, | 426 rect.height(), data_format, data_type, |
353 gles2_data ? gles2_data.get() : data); | 427 gles2_data ? gles2_data.get() : data); |
| 428 |
| 429 if (data_row_length != rect.width()) |
| 430 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); |
354 } | 431 } |
355 | 432 |
356 return true; | 433 return true; |
357 } | 434 } |
358 | 435 |
359 bool GLImageMemory::ScheduleOverlayPlane(gfx::AcceleratedWidget widget, | 436 bool GLImageMemory::ScheduleOverlayPlane(gfx::AcceleratedWidget widget, |
360 int z_order, | 437 int z_order, |
361 gfx::OverlayTransform transform, | 438 gfx::OverlayTransform transform, |
362 const gfx::Rect& bounds_rect, | 439 const gfx::Rect& bounds_rect, |
363 const gfx::RectF& crop_rect) { | 440 const gfx::RectF& crop_rect) { |
364 return false; | 441 return false; |
365 } | 442 } |
366 | 443 |
367 // static | 444 // static |
368 unsigned GLImageMemory::GetInternalFormatForTesting(BufferFormat format) { | 445 unsigned GLImageMemory::GetInternalFormatForTesting(BufferFormat format) { |
369 DCHECK(ValidFormat(format)); | 446 DCHECK(ValidFormat(format)); |
370 return TextureFormat(format); | 447 return TextureFormat(format); |
371 } | 448 } |
372 | 449 |
373 } // namespace gl | 450 } // namespace gl |
OLD | NEW |