| |
1 /* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ |
| |
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
| |
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
| |
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
5 |
| |
6 #include "GLUploadHelpers.h" |
| |
7 |
| |
8 #include "GLContext.h" |
| |
9 #include "mozilla/gfx/2D.h" |
| |
10 #include "mozilla/gfx/Tools.h" // For BytesPerPixel |
| |
11 #include "nsRegion.h" |
| |
12 |
| |
13 namespace mozilla { |
| |
14 |
| |
15 using namespace gfx; |
| |
16 |
| |
17 namespace gl { |
| |
18 |
| |
19 /* These two techniques are suggested by "Bit Twiddling Hacks" |
| |
20 */ |
| |
21 |
| |
22 /** |
| |
23 * Returns true if |aNumber| is a power of two |
| |
24 * 0 is incorreclty considered a power of two |
| |
25 */ |
| |
26 static bool |
| |
27 IsPowerOfTwo(int aNumber) |
| |
28 { |
| |
29 return (aNumber & (aNumber - 1)) == 0; |
| |
30 } |
| |
31 |
| |
32 /** |
| |
33 * Returns the first integer greater than |aNumber| which is a power of two |
| |
34 * Undefined for |aNumber| < 0 |
| |
35 */ |
| |
36 static int |
| |
37 NextPowerOfTwo(int aNumber) |
| |
38 { |
| |
39 #if defined(__arm__) |
| |
40 return 1 << (32 - __builtin_clz(aNumber - 1)); |
| |
41 #else |
| |
42 --aNumber; |
| |
43 aNumber |= aNumber >> 1; |
| |
44 aNumber |= aNumber >> 2; |
| |
45 aNumber |= aNumber >> 4; |
| |
46 aNumber |= aNumber >> 8; |
| |
47 aNumber |= aNumber >> 16; |
| |
48 return ++aNumber; |
| |
49 #endif |
| |
50 } |
| |
51 |
| |
52 static unsigned int |
| |
53 DataOffset(const nsIntPoint &aPoint, int32_t aStride, SurfaceFormat aFormat) |
| |
54 { |
| |
55 unsigned int data = aPoint.y * aStride; |
| |
56 data += aPoint.x * BytesPerPixel(aFormat); |
| |
57 return data; |
| |
58 } |
| |
59 |
| |
60 static GLint GetAddressAlignment(ptrdiff_t aAddress) |
| |
61 { |
| |
62 if (!(aAddress & 0x7)) { |
| |
63 return 8; |
| |
64 } else if (!(aAddress & 0x3)) { |
| |
65 return 4; |
| |
66 } else if (!(aAddress & 0x1)) { |
| |
67 return 2; |
| |
68 } else { |
| |
69 return 1; |
| |
70 } |
| |
71 } |
| |
72 |
| |
73 // Take texture data in a given buffer and copy it into a larger buffer, |
| |
74 // padding out the edge pixels for filtering if necessary |
| |
75 static void |
| |
76 CopyAndPadTextureData(const GLvoid* srcBuffer, |
| |
77 GLvoid* dstBuffer, |
| |
78 GLsizei srcWidth, GLsizei srcHeight, |
| |
79 GLsizei dstWidth, GLsizei dstHeight, |
| |
80 GLsizei stride, GLint pixelsize) |
| |
81 { |
| |
82 unsigned char *rowDest = static_cast<unsigned char*>(dstBuffer); |
| |
83 const unsigned char *source = static_cast<const unsigned char*>(srcBuffer); |
| |
84 |
| |
85 for (GLsizei h = 0; h < srcHeight; ++h) { |
| |
86 memcpy(rowDest, source, srcWidth * pixelsize); |
| |
87 rowDest += dstWidth * pixelsize; |
| |
88 source += stride; |
| |
89 } |
| |
90 |
| |
91 GLsizei padHeight = srcHeight; |
| |
92 |
| |
93 // Pad out an extra row of pixels so that edge filtering doesn't use garbage data |
| |
94 if (dstHeight > srcHeight) { |
| |
95 memcpy(rowDest, source - stride, srcWidth * pixelsize); |
| |
96 padHeight++; |
| |
97 } |
| |
98 |
| |
99 // Pad out an extra column of pixels |
| |
100 if (dstWidth > srcWidth) { |
| |
101 rowDest = static_cast<unsigned char*>(dstBuffer) + srcWidth * pixelsize; |
| |
102 for (GLsizei h = 0; h < padHeight; ++h) { |
| |
103 memcpy(rowDest, rowDest - pixelsize, pixelsize); |
| |
104 rowDest += dstWidth * pixelsize; |
| |
105 } |
| |
106 } |
| |
107 } |
| |
108 |
| |
109 // In both of these cases (for the Adreno at least) it is impossible |
| |
110 // to determine good or bad driver versions for POT texture uploads, |
| |
111 // so blacklist them all. Newer drivers use a different rendering |
| |
112 // string in the form "Adreno (TM) 200" and the drivers we've seen so |
| |
113 // far work fine with NPOT textures, so don't blacklist those until we |
| |
114 // have evidence of any problems with them. |
| |
115 bool |
| |
116 CanUploadSubTextures(GLContext* gl) |
| |
117 { |
| |
118 if (!gl->WorkAroundDriverBugs()) |
| |
119 return true; |
| |
120 |
| |
121 // There are certain GPUs that we don't want to use glTexSubImage2D on |
| |
122 // because that function can be very slow and/or buggy |
| |
123 if (gl->Renderer() == GLRenderer::Adreno200 || |
| |
124 gl->Renderer() == GLRenderer::Adreno205) |
| |
125 { |
| |
126 return false; |
| |
127 } |
| |
128 |
| |
129 // On PowerVR glTexSubImage does a readback, so it will be slower |
| |
130 // than just doing a glTexImage2D() directly. i.e. 26ms vs 10ms |
| |
131 if (gl->Renderer() == GLRenderer::SGX540 || |
| |
132 gl->Renderer() == GLRenderer::SGX530) |
| |
133 { |
| |
134 return false; |
| |
135 } |
| |
136 |
| |
137 return true; |
| |
138 } |
| |
139 |
| |
140 static void |
| |
141 TexSubImage2DWithUnpackSubimageGLES(GLContext* gl, |
| |
142 GLenum target, GLint level, |
| |
143 GLint xoffset, GLint yoffset, |
| |
144 GLsizei width, GLsizei height, |
| |
145 GLsizei stride, GLint pixelsize, |
| |
146 GLenum format, GLenum type, |
| |
147 const GLvoid* pixels) |
| |
148 { |
| |
149 gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, |
| |
150 std::min(GetAddressAlignment((ptrdiff_t)pixels), |
| |
151 GetAddressAlignment((ptrdiff_t)stride))); |
| |
152 // When using GL_UNPACK_ROW_LENGTH, we need to work around a Tegra |
| |
153 // driver crash where the driver apparently tries to read |
| |
154 // (stride - width * pixelsize) bytes past the end of the last input |
| |
155 // row. We only upload the first height-1 rows using GL_UNPACK_ROW_LENGTH, |
| |
156 // and then we upload the final row separately. See bug 697990. |
| |
157 int rowLength = stride/pixelsize; |
| |
158 gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength); |
| |
159 gl->fTexSubImage2D(target, |
| |
160 level, |
| |
161 xoffset, |
| |
162 yoffset, |
| |
163 width, |
| |
164 height-1, |
| |
165 format, |
| |
166 type, |
| |
167 pixels); |
| |
168 gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0); |
| |
169 gl->fTexSubImage2D(target, |
| |
170 level, |
| |
171 xoffset, |
| |
172 yoffset+height-1, |
| |
173 width, |
| |
174 1, |
| |
175 format, |
| |
176 type, |
| |
177 (const unsigned char *)pixels+(height-1)*stride); |
| |
178 gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); |
| |
179 } |
| |
180 |
| |
181 static void |
| |
182 TexSubImage2DWithoutUnpackSubimage(GLContext* gl, |
| |
183 GLenum target, GLint level, |
| |
184 GLint xoffset, GLint yoffset, |
| |
185 GLsizei width, GLsizei height, |
| |
186 GLsizei stride, GLint pixelsize, |
| |
187 GLenum format, GLenum type, |
| |
188 const GLvoid* pixels) |
| |
189 { |
| |
190 // Not using the whole row of texture data and GL_UNPACK_ROW_LENGTH |
| |
191 // isn't supported. We make a copy of the texture data we're using, |
| |
192 // such that we're using the whole row of data in the copy. This turns |
| |
193 // out to be more efficient than uploading row-by-row; see bug 698197. |
| |
194 unsigned char *newPixels = new unsigned char[width*height*pixelsize]; |
| |
195 unsigned char *rowDest = newPixels; |
| |
196 const unsigned char *rowSource = (const unsigned char *)pixels; |
| |
197 for (int h = 0; h < height; h++) { |
| |
198 memcpy(rowDest, rowSource, width*pixelsize); |
| |
199 rowDest += width*pixelsize; |
| |
200 rowSource += stride; |
| |
201 } |
| |
202 |
| |
203 stride = width*pixelsize; |
| |
204 gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, |
| |
205 std::min(GetAddressAlignment((ptrdiff_t)newPixels), |
| |
206 GetAddressAlignment((ptrdiff_t)stride))); |
| |
207 gl->fTexSubImage2D(target, |
| |
208 level, |
| |
209 xoffset, |
| |
210 yoffset, |
| |
211 width, |
| |
212 height, |
| |
213 format, |
| |
214 type, |
| |
215 newPixels); |
| |
216 delete [] newPixels; |
| |
217 gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); |
| |
218 } |
| |
219 |
| |
220 static void |
| |
221 TexSubImage2DHelper(GLContext *gl, |
| |
222 GLenum target, GLint level, |
| |
223 GLint xoffset, GLint yoffset, |
| |
224 GLsizei width, GLsizei height, GLsizei stride, |
| |
225 GLint pixelsize, GLenum format, |
| |
226 GLenum type, const GLvoid* pixels) |
| |
227 { |
| |
228 if (gl->IsGLES()) { |
| |
229 if (stride == width * pixelsize) { |
| |
230 gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, |
| |
231 std::min(GetAddressAlignment((ptrdiff_t)pixels), |
| |
232 GetAddressAlignment((ptrdiff_t)stride))); |
| |
233 gl->fTexSubImage2D(target, |
| |
234 level, |
| |
235 xoffset, |
| |
236 yoffset, |
| |
237 width, |
| |
238 height, |
| |
239 format, |
| |
240 type, |
| |
241 pixels); |
| |
242 gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); |
| |
243 } else if (gl->IsExtensionSupported(GLContext::EXT_unpack_subimage)) { |
| |
244 TexSubImage2DWithUnpackSubimageGLES(gl, target, level, xoffset, yoffset, |
| |
245 width, height, stride, |
| |
246 pixelsize, format, type, pixels); |
| |
247 |
| |
248 } else { |
| |
249 TexSubImage2DWithoutUnpackSubimage(gl, target, level, xoffset, yoffset, |
| |
250 width, height, stride, |
| |
251 pixelsize, format, type, pixels); |
| |
252 } |
| |
253 } else { |
| |
254 // desktop GL (non-ES) path |
| |
255 gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, |
| |
256 std::min(GetAddressAlignment((ptrdiff_t)pixels), |
| |
257 GetAddressAlignment((ptrdiff_t)stride))); |
| |
258 int rowLength = stride/pixelsize; |
| |
259 gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength); |
| |
260 gl->fTexSubImage2D(target, |
| |
261 level, |
| |
262 xoffset, |
| |
263 yoffset, |
| |
264 width, |
| |
265 height, |
| |
266 format, |
| |
267 type, |
| |
268 pixels); |
| |
269 gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0); |
| |
270 gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); |
| |
271 } |
| |
272 } |
| |
273 |
| |
274 static void |
| |
275 TexImage2DHelper(GLContext *gl, |
| |
276 GLenum target, GLint level, GLint internalformat, |
| |
277 GLsizei width, GLsizei height, GLsizei stride, |
| |
278 GLint pixelsize, GLint border, GLenum format, |
| |
279 GLenum type, const GLvoid *pixels) |
| |
280 { |
| |
281 if (gl->IsGLES()) { |
| |
282 |
| |
283 NS_ASSERTION(format == (GLenum)internalformat, |
| |
284 "format and internalformat not the same for glTexImage2D on GLES2"); |
| |
285 |
| |
286 if (!CanUploadNonPowerOfTwo(gl) |
| |
287 && (stride != width * pixelsize |
| |
288 || !IsPowerOfTwo(width) |
| |
289 || !IsPowerOfTwo(height))) { |
| |
290 |
| |
291 // Pad out texture width and height to the next power of two |
| |
292 // as we don't support/want non power of two texture uploads |
| |
293 GLsizei paddedWidth = NextPowerOfTwo(width); |
| |
294 GLsizei paddedHeight = NextPowerOfTwo(height); |
| |
295 |
| |
296 GLvoid* paddedPixels = new unsigned char[paddedWidth * paddedHeight * pixelsize]; |
| |
297 |
| |
298 // Pad out texture data to be in a POT sized buffer for uploading to |
| |
299 // a POT sized texture |
| |
300 CopyAndPadTextureData(pixels, paddedPixels, width, height, |
| |
301 paddedWidth, paddedHeight, stride, pixelsize); |
| |
302 |
| |
303 gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, |
| |
304 std::min(GetAddressAlignment((ptrdiff_t)paddedPixels), |
| |
305 GetAddressAlignment((ptrdiff_t)paddedWidth * pixelsize))); |
| |
306 gl->fTexImage2D(target, |
| |
307 border, |
| |
308 internalformat, |
| |
309 paddedWidth, |
| |
310 paddedHeight, |
| |
311 border, |
| |
312 format, |
| |
313 type, |
| |
314 paddedPixels); |
| |
315 gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); |
| |
316 |
| |
317 delete[] static_cast<unsigned char*>(paddedPixels); |
| |
318 return; |
| |
319 } |
| |
320 |
| |
321 if (stride == width * pixelsize) { |
| |
322 gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, |
| |
323 std::min(GetAddressAlignment((ptrdiff_t)pixels), |
| |
324 GetAddressAlignment((ptrdiff_t)stride))); |
| |
325 gl->fTexImage2D(target, |
| |
326 border, |
| |
327 internalformat, |
| |
328 width, |
| |
329 height, |
| |
330 border, |
| |
331 format, |
| |
332 type, |
| |
333 pixels); |
| |
334 gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); |
| |
335 } else { |
| |
336 // Use GLES-specific workarounds for GL_UNPACK_ROW_LENGTH; these are |
| |
337 // implemented in TexSubImage2D. |
| |
338 gl->fTexImage2D(target, |
| |
339 border, |
| |
340 internalformat, |
| |
341 width, |
| |
342 height, |
| |
343 border, |
| |
344 format, |
| |
345 type, |
| |
346 nullptr); |
| |
347 TexSubImage2DHelper(gl, |
| |
348 target, |
| |
349 level, |
| |
350 0, |
| |
351 0, |
| |
352 width, |
| |
353 height, |
| |
354 stride, |
| |
355 pixelsize, |
| |
356 format, |
| |
357 type, |
| |
358 pixels); |
| |
359 } |
| |
360 } else { |
| |
361 // desktop GL (non-ES) path |
| |
362 |
| |
363 gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, |
| |
364 std::min(GetAddressAlignment((ptrdiff_t)pixels), |
| |
365 GetAddressAlignment((ptrdiff_t)stride))); |
| |
366 int rowLength = stride/pixelsize; |
| |
367 gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength); |
| |
368 gl->fTexImage2D(target, |
| |
369 level, |
| |
370 internalformat, |
| |
371 width, |
| |
372 height, |
| |
373 border, |
| |
374 format, |
| |
375 type, |
| |
376 pixels); |
| |
377 gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0); |
| |
378 gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); |
| |
379 } |
| |
380 } |
| |
381 |
| |
382 SurfaceFormat |
| |
383 UploadImageDataToTexture(GLContext* gl, |
| |
384 unsigned char* aData, |
| |
385 int32_t aStride, |
| |
386 SurfaceFormat aFormat, |
| |
387 const nsIntRegion& aDstRegion, |
| |
388 GLuint& aTexture, |
| |
389 bool aOverwrite, |
| |
390 bool aPixelBuffer, |
| |
391 GLenum aTextureUnit, |
| |
392 GLenum aTextureTarget) |
| |
393 { |
| |
394 bool textureInited = aOverwrite ? false : true; |
| |
395 gl->MakeCurrent(); |
| |
396 gl->fActiveTexture(aTextureUnit); |
| |
397 |
| |
398 if (!aTexture) { |
| |
399 gl->fGenTextures(1, &aTexture); |
| |
400 gl->fBindTexture(aTextureTarget, aTexture); |
| |
401 gl->fTexParameteri(aTextureTarget, |
| |
402 LOCAL_GL_TEXTURE_MIN_FILTER, |
| |
403 LOCAL_GL_LINEAR); |
| |
404 gl->fTexParameteri(aTextureTarget, |
| |
405 LOCAL_GL_TEXTURE_MAG_FILTER, |
| |
406 LOCAL_GL_LINEAR); |
| |
407 gl->fTexParameteri(aTextureTarget, |
| |
408 LOCAL_GL_TEXTURE_WRAP_S, |
| |
409 LOCAL_GL_CLAMP_TO_EDGE); |
| |
410 gl->fTexParameteri(aTextureTarget, |
| |
411 LOCAL_GL_TEXTURE_WRAP_T, |
| |
412 LOCAL_GL_CLAMP_TO_EDGE); |
| |
413 textureInited = false; |
| |
414 } else { |
| |
415 gl->fBindTexture(aTextureTarget, aTexture); |
| |
416 } |
| |
417 |
| |
418 nsIntRegion paintRegion; |
| |
419 if (!textureInited) { |
| |
420 paintRegion = nsIntRegion(aDstRegion.GetBounds()); |
| |
421 } else { |
| |
422 paintRegion = aDstRegion; |
| |
423 } |
| |
424 |
| |
425 GLenum format = 0; |
| |
426 GLenum internalFormat = 0; |
| |
427 GLenum type = 0; |
| |
428 int32_t pixelSize = BytesPerPixel(aFormat); |
| |
429 SurfaceFormat surfaceFormat = gfx::SurfaceFormat::UNKNOWN; |
| |
430 |
| |
431 MOZ_ASSERT(gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA || |
| |
432 gl->GetPreferredARGB32Format() == LOCAL_GL_RGBA); |
| |
433 switch (aFormat) { |
| |
434 case SurfaceFormat::B8G8R8A8: |
| |
435 if (gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA) { |
| |
436 format = LOCAL_GL_BGRA; |
| |
437 surfaceFormat = SurfaceFormat::R8G8B8A8; |
| |
438 type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; |
| |
439 } else { |
| |
440 format = LOCAL_GL_RGBA; |
| |
441 surfaceFormat = SurfaceFormat::B8G8R8A8; |
| |
442 type = LOCAL_GL_UNSIGNED_BYTE; |
| |
443 } |
| |
444 internalFormat = LOCAL_GL_RGBA; |
| |
445 break; |
| |
446 case SurfaceFormat::B8G8R8X8: |
| |
447 // Treat BGRX surfaces as BGRA except for the surface |
| |
448 // format used. |
| |
449 if (gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA) { |
| |
450 format = LOCAL_GL_BGRA; |
| |
451 surfaceFormat = SurfaceFormat::R8G8B8X8; |
| |
452 type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; |
| |
453 } else { |
| |
454 format = LOCAL_GL_RGBA; |
| |
455 surfaceFormat = SurfaceFormat::B8G8R8X8; |
| |
456 type = LOCAL_GL_UNSIGNED_BYTE; |
| |
457 } |
| |
458 internalFormat = LOCAL_GL_RGBA; |
| |
459 break; |
| |
460 case SurfaceFormat::R5G6B5: |
| |
461 internalFormat = format = LOCAL_GL_RGB; |
| |
462 type = LOCAL_GL_UNSIGNED_SHORT_5_6_5; |
| |
463 surfaceFormat = SurfaceFormat::R5G6B5; |
| |
464 break; |
| |
465 case SurfaceFormat::A8: |
| |
466 internalFormat = format = LOCAL_GL_LUMINANCE; |
| |
467 type = LOCAL_GL_UNSIGNED_BYTE; |
| |
468 // We don't have a specific luminance shader |
| |
469 surfaceFormat = SurfaceFormat::A8; |
| |
470 break; |
| |
471 default: |
| |
472 NS_ASSERTION(false, "Unhandled image surface format!"); |
| |
473 } |
| |
474 |
| |
475 nsIntRegionRectIterator iter(paintRegion); |
| |
476 const nsIntRect *iterRect; |
| |
477 |
| |
478 // Top left point of the region's bounding rectangle. |
| |
479 nsIntPoint topLeft = paintRegion.GetBounds().TopLeft(); |
| |
480 |
| |
481 while ((iterRect = iter.Next())) { |
| |
482 // The inital data pointer is at the top left point of the region's |
| |
483 // bounding rectangle. We need to find the offset of this rect |
| |
484 // within the region and adjust the data pointer accordingly. |
| |
485 unsigned char *rectData = |
| |
486 aData + DataOffset(iterRect->TopLeft() - topLeft, aStride, aFormat); |
| |
487 |
| |
488 NS_ASSERTION(textureInited || (iterRect->x == 0 && iterRect->y == 0), |
| |
489 "Must be uploading to the origin when we don't have an existing texture"); |
| |
490 |
| |
491 if (textureInited && CanUploadSubTextures(gl)) { |
| |
492 TexSubImage2DHelper(gl, |
| |
493 aTextureTarget, |
| |
494 0, |
| |
495 iterRect->x, |
| |
496 iterRect->y, |
| |
497 iterRect->width, |
| |
498 iterRect->height, |
| |
499 aStride, |
| |
500 pixelSize, |
| |
501 format, |
| |
502 type, |
| |
503 rectData); |
| |
504 } else { |
| |
505 TexImage2DHelper(gl, |
| |
506 aTextureTarget, |
| |
507 0, |
| |
508 internalFormat, |
| |
509 iterRect->width, |
| |
510 iterRect->height, |
| |
511 aStride, |
| |
512 pixelSize, |
| |
513 0, |
| |
514 format, |
| |
515 type, |
| |
516 rectData); |
| |
517 } |
| |
518 |
| |
519 } |
| |
520 |
| |
521 return surfaceFormat; |
| |
522 } |
| |
523 |
| |
524 SurfaceFormat |
| |
525 UploadSurfaceToTexture(GLContext* gl, |
| |
526 DataSourceSurface *aSurface, |
| |
527 const nsIntRegion& aDstRegion, |
| |
528 GLuint& aTexture, |
| |
529 bool aOverwrite, |
| |
530 const nsIntPoint& aSrcPoint, |
| |
531 bool aPixelBuffer, |
| |
532 GLenum aTextureUnit, |
| |
533 GLenum aTextureTarget) |
| |
534 { |
| |
535 unsigned char* data = aPixelBuffer ? nullptr : aSurface->GetData(); |
| |
536 int32_t stride = aSurface->Stride(); |
| |
537 SurfaceFormat format = aSurface->GetFormat(); |
| |
538 data += DataOffset(aSrcPoint, stride, format); |
| |
539 return UploadImageDataToTexture(gl, data, stride, format, |
| |
540 aDstRegion, aTexture, aOverwrite, |
| |
541 aPixelBuffer, aTextureUnit, |
| |
542 aTextureTarget); |
| |
543 } |
| |
544 |
| |
545 bool |
| |
546 CanUploadNonPowerOfTwo(GLContext* gl) |
| |
547 { |
| |
548 if (!gl->WorkAroundDriverBugs()) |
| |
549 return true; |
| |
550 |
| |
551 // Some GPUs driver crash when uploading non power of two 565 textures. |
| |
552 return gl->Renderer() != GLRenderer::Adreno200 && |
| |
553 gl->Renderer() != GLRenderer::Adreno205; |
| |
554 } |
| |
555 |
| |
556 } |
| |
557 } |