1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // TextureGL.cpp: Implements the class methods for TextureGL.
8
9 #include "libANGLE/renderer/gl/TextureGL.h"
10
11 #include "common/bitset_utils.h"
12 #include "common/debug.h"
13 #include "common/utilities.h"
14 #include "libANGLE/Context.h"
15 #include "libANGLE/MemoryObject.h"
16 #include "libANGLE/State.h"
17 #include "libANGLE/Surface.h"
18 #include "libANGLE/angletypes.h"
19 #include "libANGLE/formatutils.h"
20 #include "libANGLE/queryconversions.h"
21 #include "libANGLE/renderer/gl/BlitGL.h"
22 #include "libANGLE/renderer/gl/BufferGL.h"
23 #include "libANGLE/renderer/gl/ContextGL.h"
24 #include "libANGLE/renderer/gl/FramebufferGL.h"
25 #include "libANGLE/renderer/gl/FunctionsGL.h"
26 #include "libANGLE/renderer/gl/ImageGL.h"
27 #include "libANGLE/renderer/gl/MemoryObjectGL.h"
28 #include "libANGLE/renderer/gl/StateManagerGL.h"
29 #include "libANGLE/renderer/gl/SurfaceGL.h"
30 #include "libANGLE/renderer/gl/formatutilsgl.h"
31 #include "libANGLE/renderer/gl/renderergl_utils.h"
32 #include "platform/FeaturesGL.h"
33
34 using angle::CheckedNumeric;
35
36 namespace rx
37 {
38
39 namespace
40 {
41
GetLevelInfoIndex(gl::TextureTarget target,size_t level)42 size_t GetLevelInfoIndex(gl::TextureTarget target, size_t level)
43 {
44 return gl::IsCubeMapFaceTarget(target)
45 ? ((level * gl::kCubeFaceCount) + gl::CubeMapTextureTargetToFaceIndex(target))
46 : level;
47 }
48
IsLUMAFormat(GLenum format)49 bool IsLUMAFormat(GLenum format)
50 {
51 return format == GL_LUMINANCE || format == GL_ALPHA || format == GL_LUMINANCE_ALPHA;
52 }
53
GetLUMAWorkaroundInfo(GLenum originalFormat,GLenum destinationFormat)54 LUMAWorkaroundGL GetLUMAWorkaroundInfo(GLenum originalFormat, GLenum destinationFormat)
55 {
56 if (IsLUMAFormat(originalFormat))
57 {
58 return LUMAWorkaroundGL(!IsLUMAFormat(destinationFormat), destinationFormat);
59 }
60 else
61 {
62 return LUMAWorkaroundGL(false, GL_NONE);
63 }
64 }
65
GetDepthStencilWorkaround(GLenum format)66 bool GetDepthStencilWorkaround(GLenum format)
67 {
68 return format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL;
69 }
70
GetEmulatedAlphaChannel(const angle::FeaturesGL & features,GLenum internalFormat)71 bool GetEmulatedAlphaChannel(const angle::FeaturesGL &features, GLenum internalFormat)
72 {
73 return features.rgbDXT1TexturesSampleZeroAlpha.enabled &&
74 internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
75 }
76
GetLevelInfo(const angle::FeaturesGL & features,GLenum originalInternalFormat,GLenum destinationInternalFormat)77 LevelInfoGL GetLevelInfo(const angle::FeaturesGL &features,
78 GLenum originalInternalFormat,
79 GLenum destinationInternalFormat)
80 {
81 GLenum originalFormat = gl::GetUnsizedFormat(originalInternalFormat);
82 GLenum destinationFormat = gl::GetUnsizedFormat(destinationInternalFormat);
83 return LevelInfoGL(originalFormat, destinationInternalFormat,
84 GetDepthStencilWorkaround(originalFormat),
85 GetLUMAWorkaroundInfo(originalFormat, destinationFormat),
86 GetEmulatedAlphaChannel(features, originalFormat));
87 }
88
GetLevelWorkaroundDirtyBits()89 gl::Texture::DirtyBits GetLevelWorkaroundDirtyBits()
90 {
91 gl::Texture::DirtyBits bits;
92 bits.set(gl::Texture::DIRTY_BIT_SWIZZLE_RED);
93 bits.set(gl::Texture::DIRTY_BIT_SWIZZLE_GREEN);
94 bits.set(gl::Texture::DIRTY_BIT_SWIZZLE_BLUE);
95 bits.set(gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA);
96 return bits;
97 }
98
GetMaxLevelInfoCountForTextureType(gl::TextureType type)99 size_t GetMaxLevelInfoCountForTextureType(gl::TextureType type)
100 {
101 switch (type)
102 {
103 case gl::TextureType::CubeMap:
104 return (gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1) * gl::kCubeFaceCount;
105
106 case gl::TextureType::External:
107 return 1;
108
109 default:
110 return gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1;
111 }
112 }
113
114 } // anonymous namespace
115
LUMAWorkaroundGL()116 LUMAWorkaroundGL::LUMAWorkaroundGL() : LUMAWorkaroundGL(false, GL_NONE) {}
117
LUMAWorkaroundGL(bool enabled_,GLenum workaroundFormat_)118 LUMAWorkaroundGL::LUMAWorkaroundGL(bool enabled_, GLenum workaroundFormat_)
119 : enabled(enabled_), workaroundFormat(workaroundFormat_)
120 {}
121
LevelInfoGL()122 LevelInfoGL::LevelInfoGL() : LevelInfoGL(GL_NONE, GL_NONE, false, LUMAWorkaroundGL(), false) {}
123
LevelInfoGL(GLenum sourceFormat_,GLenum nativeInternalFormat_,bool depthStencilWorkaround_,const LUMAWorkaroundGL & lumaWorkaround_,bool emulatedAlphaChannel_)124 LevelInfoGL::LevelInfoGL(GLenum sourceFormat_,
125 GLenum nativeInternalFormat_,
126 bool depthStencilWorkaround_,
127 const LUMAWorkaroundGL &lumaWorkaround_,
128 bool emulatedAlphaChannel_)
129 : sourceFormat(sourceFormat_),
130 nativeInternalFormat(nativeInternalFormat_),
131 depthStencilWorkaround(depthStencilWorkaround_),
132 lumaWorkaround(lumaWorkaround_),
133 emulatedAlphaChannel(emulatedAlphaChannel_)
134 {}
135
TextureGL(const gl::TextureState & state,GLuint id)136 TextureGL::TextureGL(const gl::TextureState &state, GLuint id)
137 : TextureImpl(state),
138 mAppliedSwizzle(state.getSwizzleState()),
139 mAppliedSampler(state.getSamplerState()),
140 mAppliedBaseLevel(state.getEffectiveBaseLevel()),
141 mAppliedMaxLevel(state.getEffectiveMaxLevel()),
142 mTextureID(id)
143 {
144 mLevelInfo.resize(GetMaxLevelInfoCountForTextureType(getType()));
145 }
146
~TextureGL()147 TextureGL::~TextureGL()
148 {
149 ASSERT(mTextureID == 0);
150 }
151
onDestroy(const gl::Context * context)152 void TextureGL::onDestroy(const gl::Context *context)
153 {
154 GetImplAs<ContextGL>(context)->flushIfNecessaryBeforeDeleteTextures();
155 StateManagerGL *stateManager = GetStateManagerGL(context);
156 stateManager->deleteTexture(mTextureID);
157 mTextureID = 0;
158 }
159
setImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)160 angle::Result TextureGL::setImage(const gl::Context *context,
161 const gl::ImageIndex &index,
162 GLenum internalFormat,
163 const gl::Extents &size,
164 GLenum format,
165 GLenum type,
166 const gl::PixelUnpackState &unpack,
167 gl::Buffer *unpackBuffer,
168 const uint8_t *pixels)
169 {
170 const angle::FeaturesGL &features = GetFeaturesGL(context);
171
172 gl::TextureTarget target = index.getTarget();
173 size_t level = static_cast<size_t>(index.getLevelIndex());
174
175 if (features.unpackOverlappingRowsSeparatelyUnpackBuffer.enabled && unpackBuffer &&
176 unpack.rowLength != 0 && unpack.rowLength < size.width)
177 {
178 // The rows overlap in unpack memory. Upload the texture row by row to work around
179 // driver bug.
180 ANGLE_TRY(
181 reserveTexImageToBeFilled(context, target, level, internalFormat, size, format, type));
182
183 if (size.width == 0 || size.height == 0 || size.depth == 0)
184 {
185 return angle::Result::Continue;
186 }
187
188 gl::Box area(0, 0, 0, size.width, size.height, size.depth);
189 return setSubImageRowByRowWorkaround(context, target, level, area, format, type, unpack,
190 unpackBuffer, 0, pixels);
191 }
192
193 if (features.unpackLastRowSeparatelyForPaddingInclusion.enabled)
194 {
195 bool apply = false;
196 ANGLE_TRY(ShouldApplyLastRowPaddingWorkaround(
197 GetImplAs<ContextGL>(context), size, unpack, unpackBuffer, format, type,
198 nativegl::UseTexImage3D(getType()), pixels, &apply));
199
200 // The driver will think the pixel buffer doesn't have enough data, work around this bug
201 // by uploading the last row (and last level if 3D) separately.
202 if (apply)
203 {
204 ANGLE_TRY(reserveTexImageToBeFilled(context, target, level, internalFormat, size,
205 format, type));
206
207 if (size.width == 0 || size.height == 0 || size.depth == 0)
208 {
209 return angle::Result::Continue;
210 }
211
212 gl::Box area(0, 0, 0, size.width, size.height, size.depth);
213 return setSubImagePaddingWorkaround(context, target, level, area, format, type, unpack,
214 unpackBuffer, pixels);
215 }
216 }
217
218 ANGLE_TRY(setImageHelper(context, target, level, internalFormat, size, format, type, pixels));
219
220 return angle::Result::Continue;
221 }
222
setImageHelper(const gl::Context * context,gl::TextureTarget target,size_t level,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type,const uint8_t * pixels)223 angle::Result TextureGL::setImageHelper(const gl::Context *context,
224 gl::TextureTarget target,
225 size_t level,
226 GLenum internalFormat,
227 const gl::Extents &size,
228 GLenum format,
229 GLenum type,
230 const uint8_t *pixels)
231 {
232 ASSERT(TextureTargetToType(target) == getType());
233
234 const FunctionsGL *functions = GetFunctionsGL(context);
235 StateManagerGL *stateManager = GetStateManagerGL(context);
236 const angle::FeaturesGL &features = GetFeaturesGL(context);
237
238 nativegl::TexImageFormat texImageFormat =
239 nativegl::GetTexImageFormat(functions, features, internalFormat, format, type);
240
241 stateManager->bindTexture(getType(), mTextureID);
242
243 if (features.resetTexImage2DBaseLevel.enabled)
244 {
245 // setBaseLevel doesn't ever generate errors.
246 (void)setBaseLevel(context, 0);
247 }
248
249 if (nativegl::UseTexImage2D(getType()))
250 {
251 ASSERT(size.depth == 1);
252 ANGLE_GL_TRY_ALWAYS_CHECK(
253 context, functions->texImage2D(nativegl::GetTextureBindingTarget(target),
254 static_cast<GLint>(level), texImageFormat.internalFormat,
255 size.width, size.height, 0, texImageFormat.format,
256 texImageFormat.type, pixels));
257 }
258 else
259 {
260 ASSERT(nativegl::UseTexImage3D(getType()));
261 ANGLE_GL_TRY_ALWAYS_CHECK(
262 context, functions->texImage3D(ToGLenum(target), static_cast<GLint>(level),
263 texImageFormat.internalFormat, size.width, size.height,
264 size.depth, 0, texImageFormat.format,
265 texImageFormat.type, pixels));
266 }
267
268 LevelInfoGL levelInfo = GetLevelInfo(features, internalFormat, texImageFormat.internalFormat);
269 setLevelInfo(context, target, level, 1, levelInfo);
270
271 if (features.setZeroLevelBeforeGenerateMipmap.enabled && getType() == gl::TextureType::_2D &&
272 level != 0 && mLevelInfo[0].nativeInternalFormat == GL_NONE)
273 {
274 // Only fill level zero if it's possible that mipmaps can be generated with this format
275 const gl::InternalFormat &internalFormatInfo =
276 gl::GetInternalFormatInfo(internalFormat, type);
277 if (!internalFormatInfo.sized ||
278 (internalFormatInfo.filterSupport(context->getClientVersion(),
279 context->getExtensions()) &&
280 internalFormatInfo.textureAttachmentSupport(context->getClientVersion(),
281 context->getExtensions())))
282 {
283 ANGLE_GL_TRY_ALWAYS_CHECK(
284 context,
285 functions->texImage2D(nativegl::GetTextureBindingTarget(target), 0,
286 texImageFormat.internalFormat, 1, 1, 0, texImageFormat.format,
287 texImageFormat.type, nullptr));
288 setLevelInfo(context, target, 0, 1, levelInfo);
289 }
290 }
291
292 return angle::Result::Continue;
293 }
294
reserveTexImageToBeFilled(const gl::Context * context,gl::TextureTarget target,size_t level,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type)295 angle::Result TextureGL::reserveTexImageToBeFilled(const gl::Context *context,
296 gl::TextureTarget target,
297 size_t level,
298 GLenum internalFormat,
299 const gl::Extents &size,
300 GLenum format,
301 GLenum type)
302 {
303 StateManagerGL *stateManager = GetStateManagerGL(context);
304 ANGLE_TRY(stateManager->setPixelUnpackBuffer(context, nullptr));
305 ANGLE_TRY(setImageHelper(context, target, level, internalFormat, size, format, type, nullptr));
306 return angle::Result::Continue;
307 }
308
setSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)309 angle::Result TextureGL::setSubImage(const gl::Context *context,
310 const gl::ImageIndex &index,
311 const gl::Box &area,
312 GLenum format,
313 GLenum type,
314 const gl::PixelUnpackState &unpack,
315 gl::Buffer *unpackBuffer,
316 const uint8_t *pixels)
317 {
318 ASSERT(TextureTargetToType(index.getTarget()) == getType());
319
320 const FunctionsGL *functions = GetFunctionsGL(context);
321 StateManagerGL *stateManager = GetStateManagerGL(context);
322 const angle::FeaturesGL &features = GetFeaturesGL(context);
323
324 nativegl::TexSubImageFormat texSubImageFormat =
325 nativegl::GetTexSubImageFormat(functions, features, format, type);
326
327 gl::TextureTarget target = index.getTarget();
328 size_t level = static_cast<size_t>(index.getLevelIndex());
329
330 ASSERT(getLevelInfo(target, level).lumaWorkaround.enabled ==
331 GetLevelInfo(features, format, texSubImageFormat.format).lumaWorkaround.enabled);
332
333 stateManager->bindTexture(getType(), mTextureID);
334 if (features.unpackOverlappingRowsSeparatelyUnpackBuffer.enabled && unpackBuffer &&
335 unpack.rowLength != 0 && unpack.rowLength < area.width)
336 {
337 return setSubImageRowByRowWorkaround(context, target, level, area, format, type, unpack,
338 unpackBuffer, 0, pixels);
339 }
340
341 if (features.unpackLastRowSeparatelyForPaddingInclusion.enabled)
342 {
343 gl::Extents size(area.width, area.height, area.depth);
344
345 bool apply = false;
346 ANGLE_TRY(ShouldApplyLastRowPaddingWorkaround(
347 GetImplAs<ContextGL>(context), size, unpack, unpackBuffer, format, type,
348 nativegl::UseTexImage3D(getType()), pixels, &apply));
349
350 // The driver will think the pixel buffer doesn't have enough data, work around this bug
351 // by uploading the last row (and last level if 3D) separately.
352 if (apply)
353 {
354 return setSubImagePaddingWorkaround(context, target, level, area, format, type, unpack,
355 unpackBuffer, pixels);
356 }
357 }
358
359 if (features.uploadTextureDataInChunks.enabled)
360 {
361 return setSubImageRowByRowWorkaround(
362 context, target, level, area, format, type, unpack, unpackBuffer,
363 angle::FeaturesGL::kUploadTextureDataInChunksUploadSize, pixels);
364 }
365
366 if (nativegl::UseTexImage2D(getType()))
367 {
368 ASSERT(area.z == 0 && area.depth == 1);
369 ANGLE_GL_TRY(context,
370 functions->texSubImage2D(nativegl::GetTextureBindingTarget(target),
371 static_cast<GLint>(level), area.x, area.y, area.width,
372 area.height, texSubImageFormat.format,
373 texSubImageFormat.type, pixels));
374 }
375 else
376 {
377 ASSERT(nativegl::UseTexImage3D(getType()));
378 ANGLE_GL_TRY(context, functions->texSubImage3D(
379 ToGLenum(target), static_cast<GLint>(level), area.x, area.y,
380 area.z, area.width, area.height, area.depth,
381 texSubImageFormat.format, texSubImageFormat.type, pixels));
382 }
383
384 return angle::Result::Continue;
385 }
386
setSubImageRowByRowWorkaround(const gl::Context * context,gl::TextureTarget target,size_t level,const gl::Box & area,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,const gl::Buffer * unpackBuffer,size_t maxBytesUploadedPerChunk,const uint8_t * pixels)387 angle::Result TextureGL::setSubImageRowByRowWorkaround(const gl::Context *context,
388 gl::TextureTarget target,
389 size_t level,
390 const gl::Box &area,
391 GLenum format,
392 GLenum type,
393 const gl::PixelUnpackState &unpack,
394 const gl::Buffer *unpackBuffer,
395 size_t maxBytesUploadedPerChunk,
396 const uint8_t *pixels)
397 {
398 ContextGL *contextGL = GetImplAs<ContextGL>(context);
399 const FunctionsGL *functions = GetFunctionsGL(context);
400 StateManagerGL *stateManager = GetStateManagerGL(context);
401 const angle::FeaturesGL &features = GetFeaturesGL(context);
402
403 gl::PixelUnpackState directUnpack = unpack;
404 directUnpack.skipRows = 0;
405 directUnpack.skipPixels = 0;
406 directUnpack.skipImages = 0;
407 ANGLE_TRY(stateManager->setPixelUnpackState(context, directUnpack));
408 ANGLE_TRY(stateManager->setPixelUnpackBuffer(context, unpackBuffer));
409
410 const gl::InternalFormat &glFormat = gl::GetInternalFormatInfo(format, type);
411 GLuint rowBytes = 0;
412 ANGLE_CHECK_GL_MATH(contextGL, glFormat.computeRowPitch(type, area.width, unpack.alignment,
413 unpack.rowLength, &rowBytes));
414 GLuint imageBytes = 0;
415 ANGLE_CHECK_GL_MATH(contextGL, glFormat.computeDepthPitch(area.height, unpack.imageHeight,
416 rowBytes, &imageBytes));
417
418 bool useTexImage3D = nativegl::UseTexImage3D(getType());
419 GLuint skipBytes = 0;
420 ANGLE_CHECK_GL_MATH(contextGL, glFormat.computeSkipBytes(type, rowBytes, imageBytes, unpack,
421 useTexImage3D, &skipBytes));
422
423 GLint rowsPerChunk =
424 std::min(std::max(static_cast<GLint>(maxBytesUploadedPerChunk / rowBytes), 1), area.height);
425 if (maxBytesUploadedPerChunk > 0 && rowsPerChunk < area.height)
426 {
427 ANGLE_PERF_WARNING(contextGL->getDebug(), GL_DEBUG_SEVERITY_LOW,
428 "Chunking upload of texture data to work around driver hangs.");
429 }
430
431 nativegl::TexSubImageFormat texSubImageFormat =
432 nativegl::GetTexSubImageFormat(functions, features, format, type);
433
434 const uint8_t *pixelsWithSkip = pixels + skipBytes;
435 if (useTexImage3D)
436 {
437 for (GLint image = 0; image < area.depth; ++image)
438 {
439 GLint imageByteOffset = image * imageBytes;
440 for (GLint row = 0; row < area.height; row += rowsPerChunk)
441 {
442 GLint height = std::min(rowsPerChunk, area.height - row);
443 GLint byteOffset = imageByteOffset + row * rowBytes;
444 const GLubyte *rowPixels = pixelsWithSkip + byteOffset;
445 ANGLE_GL_TRY(context,
446 functions->texSubImage3D(
447 ToGLenum(target), static_cast<GLint>(level), area.x, row + area.y,
448 image + area.z, area.width, height, 1, texSubImageFormat.format,
449 texSubImageFormat.type, rowPixels));
450 }
451 }
452 }
453 else
454 {
455 ASSERT(nativegl::UseTexImage2D(getType()));
456 for (GLint row = 0; row < area.height; row += rowsPerChunk)
457 {
458 GLint height = std::min(rowsPerChunk, area.height - row);
459 GLint byteOffset = row * rowBytes;
460 const GLubyte *rowPixels = pixelsWithSkip + byteOffset;
461 ANGLE_GL_TRY(context, functions->texSubImage2D(
462 ToGLenum(target), static_cast<GLint>(level), area.x,
463 row + area.y, area.width, height, texSubImageFormat.format,
464 texSubImageFormat.type, rowPixels));
465 }
466 }
467 return angle::Result::Continue;
468 }
469
setSubImagePaddingWorkaround(const gl::Context * context,gl::TextureTarget target,size_t level,const gl::Box & area,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,const gl::Buffer * unpackBuffer,const uint8_t * pixels)470 angle::Result TextureGL::setSubImagePaddingWorkaround(const gl::Context *context,
471 gl::TextureTarget target,
472 size_t level,
473 const gl::Box &area,
474 GLenum format,
475 GLenum type,
476 const gl::PixelUnpackState &unpack,
477 const gl::Buffer *unpackBuffer,
478 const uint8_t *pixels)
479 {
480 ContextGL *contextGL = GetImplAs<ContextGL>(context);
481 const FunctionsGL *functions = GetFunctionsGL(context);
482 StateManagerGL *stateManager = GetStateManagerGL(context);
483
484 const gl::InternalFormat &glFormat = gl::GetInternalFormatInfo(format, type);
485 GLuint rowBytes = 0;
486 ANGLE_CHECK_GL_MATH(contextGL, glFormat.computeRowPitch(type, area.width, unpack.alignment,
487 unpack.rowLength, &rowBytes));
488 GLuint imageBytes = 0;
489 ANGLE_CHECK_GL_MATH(contextGL, glFormat.computeDepthPitch(area.height, unpack.imageHeight,
490 rowBytes, &imageBytes));
491 bool useTexImage3D = nativegl::UseTexImage3D(getType());
492 GLuint skipBytes = 0;
493 ANGLE_CHECK_GL_MATH(contextGL, glFormat.computeSkipBytes(type, rowBytes, imageBytes, unpack,
494 useTexImage3D, &skipBytes));
495
496 ANGLE_TRY(stateManager->setPixelUnpackState(context, unpack));
497 ANGLE_TRY(stateManager->setPixelUnpackBuffer(context, unpackBuffer));
498
499 gl::PixelUnpackState directUnpack;
500 directUnpack.alignment = 1;
501
502 if (useTexImage3D)
503 {
504 // Upload all but the last slice
505 if (area.depth > 1)
506 {
507 ANGLE_GL_TRY(context,
508 functions->texSubImage3D(ToGLenum(target), static_cast<GLint>(level),
509 area.x, area.y, area.z, area.width, area.height,
510 area.depth - 1, format, type, pixels));
511 }
512
513 // Upload the last slice but its last row
514 if (area.height > 1)
515 {
516 // Do not include skipBytes in the last image pixel start offset as it will be done by
517 // the driver
518 GLint lastImageOffset = (area.depth - 1) * imageBytes;
519 const GLubyte *lastImagePixels = pixels + lastImageOffset;
520 ANGLE_GL_TRY(context, functions->texSubImage3D(
521 ToGLenum(target), static_cast<GLint>(level), area.x, area.y,
522 area.z + area.depth - 1, area.width, area.height - 1, 1,
523 format, type, lastImagePixels));
524 }
525
526 // Upload the last row of the last slice "manually"
527 ANGLE_TRY(stateManager->setPixelUnpackState(context, directUnpack));
528
529 GLint lastRowOffset =
530 skipBytes + (area.depth - 1) * imageBytes + (area.height - 1) * rowBytes;
531 const GLubyte *lastRowPixels = pixels + lastRowOffset;
532 ANGLE_GL_TRY(context,
533 functions->texSubImage3D(ToGLenum(target), static_cast<GLint>(level), area.x,
534 area.y + area.height - 1, area.z + area.depth - 1,
535 area.width, 1, 1, format, type, lastRowPixels));
536 }
537 else
538 {
539 ASSERT(nativegl::UseTexImage2D(getType()));
540
541 // Upload all but the last row
542 if (area.height > 1)
543 {
544 ANGLE_GL_TRY(context, functions->texSubImage2D(
545 ToGLenum(target), static_cast<GLint>(level), area.x, area.y,
546 area.width, area.height - 1, format, type, pixels));
547 }
548
549 // Upload the last row "manually"
550 ANGLE_TRY(stateManager->setPixelUnpackState(context, directUnpack));
551
552 GLint lastRowOffset = skipBytes + (area.height - 1) * rowBytes;
553 const GLubyte *lastRowPixels = pixels + lastRowOffset;
554 ANGLE_GL_TRY(context, functions->texSubImage2D(ToGLenum(target), static_cast<GLint>(level),
555 area.x, area.y + area.height - 1, area.width,
556 1, format, type, lastRowPixels));
557 }
558
559 return angle::Result::Continue;
560 }
561
setCompressedImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)562 angle::Result TextureGL::setCompressedImage(const gl::Context *context,
563 const gl::ImageIndex &index,
564 GLenum internalFormat,
565 const gl::Extents &size,
566 const gl::PixelUnpackState &unpack,
567 size_t imageSize,
568 const uint8_t *pixels)
569 {
570 const FunctionsGL *functions = GetFunctionsGL(context);
571 StateManagerGL *stateManager = GetStateManagerGL(context);
572 const angle::FeaturesGL &features = GetFeaturesGL(context);
573
574 gl::TextureTarget target = index.getTarget();
575 size_t level = static_cast<size_t>(index.getLevelIndex());
576 ASSERT(TextureTargetToType(target) == getType());
577
578 nativegl::CompressedTexImageFormat compressedTexImageFormat =
579 nativegl::GetCompressedTexImageFormat(functions, features, internalFormat);
580
581 stateManager->bindTexture(getType(), mTextureID);
582 if (nativegl::UseTexImage2D(getType()))
583 {
584 ASSERT(size.depth == 1);
585 ANGLE_GL_TRY_ALWAYS_CHECK(
586 context, functions->compressedTexImage2D(ToGLenum(target), static_cast<GLint>(level),
587 compressedTexImageFormat.internalFormat,
588 size.width, size.height, 0,
589 static_cast<GLsizei>(imageSize), pixels));
590 }
591 else
592 {
593 ASSERT(nativegl::UseTexImage3D(getType()));
594 ANGLE_GL_TRY_ALWAYS_CHECK(
595 context, functions->compressedTexImage3D(ToGLenum(target), static_cast<GLint>(level),
596 compressedTexImageFormat.internalFormat,
597 size.width, size.height, size.depth, 0,
598 static_cast<GLsizei>(imageSize), pixels));
599 }
600
601 LevelInfoGL levelInfo =
602 GetLevelInfo(features, internalFormat, compressedTexImageFormat.internalFormat);
603 ASSERT(!levelInfo.lumaWorkaround.enabled);
604 setLevelInfo(context, target, level, 1, levelInfo);
605
606 return angle::Result::Continue;
607 }
608
setCompressedSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)609 angle::Result TextureGL::setCompressedSubImage(const gl::Context *context,
610 const gl::ImageIndex &index,
611 const gl::Box &area,
612 GLenum format,
613 const gl::PixelUnpackState &unpack,
614 size_t imageSize,
615 const uint8_t *pixels)
616 {
617 const FunctionsGL *functions = GetFunctionsGL(context);
618 StateManagerGL *stateManager = GetStateManagerGL(context);
619 const angle::FeaturesGL &features = GetFeaturesGL(context);
620
621 gl::TextureTarget target = index.getTarget();
622 size_t level = static_cast<size_t>(index.getLevelIndex());
623 ASSERT(TextureTargetToType(target) == getType());
624
625 nativegl::CompressedTexSubImageFormat compressedTexSubImageFormat =
626 nativegl::GetCompressedSubTexImageFormat(functions, features, format);
627
628 stateManager->bindTexture(getType(), mTextureID);
629 if (nativegl::UseTexImage2D(getType()))
630 {
631 ASSERT(area.z == 0 && area.depth == 1);
632 ANGLE_GL_TRY(context, functions->compressedTexSubImage2D(
633 ToGLenum(target), static_cast<GLint>(level), area.x, area.y,
634 area.width, area.height, compressedTexSubImageFormat.format,
635 static_cast<GLsizei>(imageSize), pixels));
636 }
637 else
638 {
639 ASSERT(nativegl::UseTexImage3D(getType()));
640 ANGLE_GL_TRY(context,
641 functions->compressedTexSubImage3D(
642 ToGLenum(target), static_cast<GLint>(level), area.x, area.y, area.z,
643 area.width, area.height, area.depth, compressedTexSubImageFormat.format,
644 static_cast<GLsizei>(imageSize), pixels));
645 }
646
647 ASSERT(
648 !getLevelInfo(target, level).lumaWorkaround.enabled &&
649 !GetLevelInfo(features, format, compressedTexSubImageFormat.format).lumaWorkaround.enabled);
650
651 return angle::Result::Continue;
652 }
653
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)654 angle::Result TextureGL::copyImage(const gl::Context *context,
655 const gl::ImageIndex &index,
656 const gl::Rectangle &sourceArea,
657 GLenum internalFormat,
658 gl::Framebuffer *source)
659 {
660 ContextGL *contextGL = GetImplAs<ContextGL>(context);
661 const FunctionsGL *functions = GetFunctionsGL(context);
662 StateManagerGL *stateManager = GetStateManagerGL(context);
663 const angle::FeaturesGL &features = GetFeaturesGL(context);
664
665 gl::TextureTarget target = index.getTarget();
666 size_t level = static_cast<size_t>(index.getLevelIndex());
667 GLenum type = source->getImplementationColorReadType(context);
668 nativegl::CopyTexImageImageFormat copyTexImageFormat =
669 nativegl::GetCopyTexImageImageFormat(functions, features, internalFormat, type);
670
671 stateManager->bindTexture(getType(), mTextureID);
672
673 const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(source);
674 gl::Extents fbSize = sourceFramebufferGL->getState().getReadAttachment()->getSize();
675
676 // Did the read area go outside the framebuffer?
677 bool outside = sourceArea.x < 0 || sourceArea.y < 0 ||
678 sourceArea.x + sourceArea.width > fbSize.width ||
679 sourceArea.y + sourceArea.height > fbSize.height;
680
681 // TODO: Find a way to initialize the texture entirely in the gl level with ensureInitialized.
682 // Right now there is no easy way to pre-fill the texture when it is being redefined with
683 // partially uninitialized data.
684 bool requiresInitialization =
685 outside && (context->isRobustResourceInitEnabled() || context->isWebGL());
686
687 // When robust resource initialization is enabled, the area outside the framebuffer must be
688 // zeroed. We just zero the whole thing before copying into the area that overlaps the
689 // framebuffer.
690 if (requiresInitialization)
691 {
692 GLuint pixelBytes =
693 gl::GetInternalFormatInfo(copyTexImageFormat.internalFormat, type).pixelBytes;
694 angle::MemoryBuffer *zero;
695 ANGLE_CHECK_GL_ALLOC(
696 contextGL,
697 context->getZeroFilledBuffer(sourceArea.width * sourceArea.height * pixelBytes, &zero));
698
699 gl::PixelUnpackState unpack;
700 unpack.alignment = 1;
701 ANGLE_TRY(stateManager->setPixelUnpackState(context, unpack));
702 ANGLE_TRY(stateManager->setPixelUnpackBuffer(context, nullptr));
703
704 ANGLE_GL_TRY_ALWAYS_CHECK(
705 context, functions->texImage2D(ToGLenum(target), static_cast<GLint>(level),
706 copyTexImageFormat.internalFormat, sourceArea.width,
707 sourceArea.height, 0,
708 gl::GetUnsizedFormat(copyTexImageFormat.internalFormat),
709 type, zero->data()));
710 }
711
712 // Clip source area to framebuffer and copy if remaining area is not empty.
713 gl::Rectangle clippedArea;
714 if (ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
715 {
716 // If fbo's read buffer and the target texture are the same texture but different levels,
717 // and if the read buffer is a non-base texture level, then implementations glTexImage2D
718 // may change the target texture and make the original texture mipmap incomplete, which in
719 // turn makes the fbo incomplete.
720 // To avoid that, we clamp BASE_LEVEL and MAX_LEVEL to the same texture level as the fbo's
721 // read buffer attachment. See http://crbug.com/797235
722 const gl::FramebufferAttachment *readBuffer = source->getReadColorAttachment();
723 if (readBuffer && readBuffer->type() == GL_TEXTURE)
724 {
725 TextureGL *sourceTexture = GetImplAs<TextureGL>(readBuffer->getTexture());
726 if (sourceTexture && sourceTexture->mTextureID == mTextureID)
727 {
728 GLuint attachedTextureLevel = readBuffer->mipLevel();
729 if (attachedTextureLevel != mState.getEffectiveBaseLevel())
730 {
731 ANGLE_TRY(setBaseLevel(context, attachedTextureLevel));
732 ANGLE_TRY(setMaxLevel(context, attachedTextureLevel));
733 }
734 }
735 }
736
737 LevelInfoGL levelInfo =
738 GetLevelInfo(features, internalFormat, copyTexImageFormat.internalFormat);
739 gl::Offset destOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y, 0);
740
741 if (levelInfo.lumaWorkaround.enabled)
742 {
743 BlitGL *blitter = GetBlitGL(context);
744
745 if (requiresInitialization)
746 {
747 ANGLE_TRY(blitter->copySubImageToLUMAWorkaroundTexture(
748 context, mTextureID, getType(), target, levelInfo.sourceFormat, level,
749 destOffset, clippedArea, source));
750 }
751 else
752 {
753 ANGLE_TRY(blitter->copyImageToLUMAWorkaroundTexture(
754 context, mTextureID, getType(), target, levelInfo.sourceFormat, level,
755 clippedArea, copyTexImageFormat.internalFormat, source));
756 }
757 }
758 else
759 {
760 ASSERT(nativegl::UseTexImage2D(getType()));
761 stateManager->bindFramebuffer(GL_READ_FRAMEBUFFER,
762 sourceFramebufferGL->getFramebufferID());
763 if (features.emulateCopyTexImage2DFromRenderbuffers.enabled && readBuffer &&
764 readBuffer->type() == GL_RENDERBUFFER)
765 {
766 BlitGL *blitter = GetBlitGL(context);
767 ANGLE_TRY(blitter->blitColorBufferWithShader(
768 context, source, mTextureID, target, level, clippedArea,
769 gl::Rectangle(destOffset.x, destOffset.y, clippedArea.width,
770 clippedArea.height),
771 GL_NEAREST, true));
772 }
773 else if (requiresInitialization)
774 {
775 ANGLE_GL_TRY(context, functions->copyTexSubImage2D(
776 ToGLenum(target), static_cast<GLint>(level), destOffset.x,
777 destOffset.y, clippedArea.x, clippedArea.y,
778 clippedArea.width, clippedArea.height));
779 }
780 else
781 {
782 ANGLE_GL_TRY_ALWAYS_CHECK(
783 context, functions->copyTexImage2D(ToGLenum(target), static_cast<GLint>(level),
784 copyTexImageFormat.internalFormat,
785 clippedArea.x, clippedArea.y,
786 clippedArea.width, clippedArea.height, 0));
787 }
788 }
789 setLevelInfo(context, target, level, 1, levelInfo);
790 }
791
792 if (features.flushBeforeDeleteTextureIfCopiedTo.enabled)
793 {
794 contextGL->setNeedsFlushBeforeDeleteTextures();
795 }
796
797 return angle::Result::Continue;
798 }
799
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)800 angle::Result TextureGL::copySubImage(const gl::Context *context,
801 const gl::ImageIndex &index,
802 const gl::Offset &destOffset,
803 const gl::Rectangle &sourceArea,
804 gl::Framebuffer *source)
805 {
806 const FunctionsGL *functions = GetFunctionsGL(context);
807 StateManagerGL *stateManager = GetStateManagerGL(context);
808 const angle::FeaturesGL &features = GetFeaturesGL(context);
809
810 gl::TextureTarget target = index.getTarget();
811 size_t level = static_cast<size_t>(index.getLevelIndex());
812 const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(source);
813
814 // Clip source area to framebuffer.
815 const gl::Extents fbSize = sourceFramebufferGL->getState().getReadAttachment()->getSize();
816 gl::Rectangle clippedArea;
817 if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
818 {
819 // nothing to do
820 return angle::Result::Continue;
821 }
822 gl::Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x,
823 destOffset.y + clippedArea.y - sourceArea.y, destOffset.z);
824
825 stateManager->bindTexture(getType(), mTextureID);
826 GLenum framebufferTarget =
827 stateManager->getHasSeparateFramebufferBindings() ? GL_READ_FRAMEBUFFER : GL_FRAMEBUFFER;
828 stateManager->bindFramebuffer(framebufferTarget, sourceFramebufferGL->getFramebufferID());
829
830 const LevelInfoGL &levelInfo = getLevelInfo(target, level);
831 if (levelInfo.lumaWorkaround.enabled)
832 {
833 BlitGL *blitter = GetBlitGL(context);
834 ANGLE_TRY(blitter->copySubImageToLUMAWorkaroundTexture(
835 context, mTextureID, getType(), target, levelInfo.sourceFormat, level, clippedOffset,
836 clippedArea, source));
837 }
838 else
839 {
840 if (nativegl::UseTexImage2D(getType()))
841 {
842 ASSERT(clippedOffset.z == 0);
843 if (features.emulateCopyTexImage2DFromRenderbuffers.enabled &&
844 source->getReadColorAttachment() &&
845 source->getReadColorAttachment()->type() == GL_RENDERBUFFER)
846 {
847 BlitGL *blitter = GetBlitGL(context);
848 ANGLE_TRY(blitter->blitColorBufferWithShader(
849 context, source, mTextureID, target, level, clippedArea,
850 gl::Rectangle(clippedOffset.x, clippedOffset.y, clippedArea.width,
851 clippedArea.height),
852 GL_NEAREST, true));
853 }
854 else
855 {
856 ANGLE_GL_TRY(context, functions->copyTexSubImage2D(
857 ToGLenum(target), static_cast<GLint>(level),
858 clippedOffset.x, clippedOffset.y, clippedArea.x,
859 clippedArea.y, clippedArea.width, clippedArea.height));
860 }
861 }
862 else
863 {
864 ASSERT(nativegl::UseTexImage3D(getType()));
865 ANGLE_GL_TRY(context, functions->copyTexSubImage3D(
866 ToGLenum(target), static_cast<GLint>(level), clippedOffset.x,
867 clippedOffset.y, clippedOffset.z, clippedArea.x,
868 clippedArea.y, clippedArea.width, clippedArea.height));
869 }
870 }
871
872 if (features.flushBeforeDeleteTextureIfCopiedTo.enabled)
873 {
874 ContextGL *contextGL = GetImplAs<ContextGL>(context);
875 contextGL->setNeedsFlushBeforeDeleteTextures();
876 }
877
878 return angle::Result::Continue;
879 }
880
copyTexture(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,GLenum type,GLint sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)881 angle::Result TextureGL::copyTexture(const gl::Context *context,
882 const gl::ImageIndex &index,
883 GLenum internalFormat,
884 GLenum type,
885 GLint sourceLevel,
886 bool unpackFlipY,
887 bool unpackPremultiplyAlpha,
888 bool unpackUnmultiplyAlpha,
889 const gl::Texture *source)
890 {
891 gl::TextureTarget target = index.getTarget();
892 size_t level = static_cast<size_t>(index.getLevelIndex());
893 const TextureGL *sourceGL = GetImplAs<TextureGL>(source);
894 const gl::ImageDesc &sourceImageDesc =
895 sourceGL->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), sourceLevel);
896 gl::Rectangle sourceArea(0, 0, sourceImageDesc.size.width, sourceImageDesc.size.height);
897
898 ANGLE_TRY(reserveTexImageToBeFilled(context, target, level, internalFormat,
899 sourceImageDesc.size, gl::GetUnsizedFormat(internalFormat),
900 type));
901
902 const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
903 return copySubTextureHelper(context, target, level, gl::Offset(0, 0, 0), sourceLevel,
904 sourceArea, destFormatInfo, unpackFlipY, unpackPremultiplyAlpha,
905 unpackUnmultiplyAlpha, source);
906 }
907
copySubTexture(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,GLint sourceLevel,const gl::Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)908 angle::Result TextureGL::copySubTexture(const gl::Context *context,
909 const gl::ImageIndex &index,
910 const gl::Offset &destOffset,
911 GLint sourceLevel,
912 const gl::Box &sourceBox,
913 bool unpackFlipY,
914 bool unpackPremultiplyAlpha,
915 bool unpackUnmultiplyAlpha,
916 const gl::Texture *source)
917 {
918 gl::TextureTarget target = index.getTarget();
919 size_t level = static_cast<size_t>(index.getLevelIndex());
920 const gl::InternalFormat &destFormatInfo = *mState.getImageDesc(target, level).format.info;
921 return copySubTextureHelper(context, target, level, destOffset, sourceLevel, sourceBox.toRect(),
922 destFormatInfo, unpackFlipY, unpackPremultiplyAlpha,
923 unpackUnmultiplyAlpha, source);
924 }
925
copySubTextureHelper(const gl::Context * context,gl::TextureTarget target,size_t level,const gl::Offset & destOffset,GLint sourceLevel,const gl::Rectangle & sourceArea,const gl::InternalFormat & destFormat,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)926 angle::Result TextureGL::copySubTextureHelper(const gl::Context *context,
927 gl::TextureTarget target,
928 size_t level,
929 const gl::Offset &destOffset,
930 GLint sourceLevel,
931 const gl::Rectangle &sourceArea,
932 const gl::InternalFormat &destFormat,
933 bool unpackFlipY,
934 bool unpackPremultiplyAlpha,
935 bool unpackUnmultiplyAlpha,
936 const gl::Texture *source)
937 {
938 const FunctionsGL *functions = GetFunctionsGL(context);
939 const angle::FeaturesGL &features = GetFeaturesGL(context);
940 BlitGL *blitter = GetBlitGL(context);
941
942 TextureGL *sourceGL = GetImplAs<TextureGL>(source);
943 const gl::ImageDesc &sourceImageDesc =
944 sourceGL->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), sourceLevel);
945
946 if (features.flushBeforeDeleteTextureIfCopiedTo.enabled)
947 {
948 // Conservatively indicate that this workaround is necessary. Not clear
949 // if it is on this code path, but added for symmetry.
950 ContextGL *contextGL = GetImplAs<ContextGL>(context);
951 contextGL->setNeedsFlushBeforeDeleteTextures();
952 }
953
954 // Check is this is a simple copySubTexture that can be done with a copyTexSubImage
955 ASSERT(sourceGL->getType() == gl::TextureType::_2D ||
956 source->getType() == gl::TextureType::External ||
957 source->getType() == gl::TextureType::Rectangle);
958 const LevelInfoGL &sourceLevelInfo =
959 sourceGL->getLevelInfo(NonCubeTextureTypeToTarget(source->getType()), sourceLevel);
960 bool needsLumaWorkaround = sourceLevelInfo.lumaWorkaround.enabled;
961
962 const gl::InternalFormat &sourceFormatInfo = *sourceImageDesc.format.info;
963 GLenum sourceFormat = sourceFormatInfo.format;
964 bool sourceFormatContainSupersetOfDestFormat =
965 (sourceFormat == destFormat.format && sourceFormat != GL_BGRA_EXT) ||
966 (sourceFormat == GL_RGBA && destFormat.format == GL_RGB);
967
968 GLenum sourceComponentType = sourceFormatInfo.componentType;
969 GLenum destComponentType = destFormat.componentType;
970 bool destSRGB = destFormat.colorEncoding == GL_SRGB;
971 if (!unpackFlipY && unpackPremultiplyAlpha == unpackUnmultiplyAlpha && !needsLumaWorkaround &&
972 sourceFormatContainSupersetOfDestFormat && sourceComponentType == destComponentType &&
973 !destSRGB && sourceGL->getType() == gl::TextureType::_2D)
974 {
975 bool copySucceeded = false;
976 ANGLE_TRY(blitter->copyTexSubImage(context, sourceGL, sourceLevel, this, target, level,
977 sourceArea, destOffset, ©Succeeded));
978 if (copySucceeded)
979 {
980 return angle::Result::Continue;
981 }
982 }
983
984 // Check if the destination is renderable and copy on the GPU
985 const LevelInfoGL &destLevelInfo = getLevelInfo(target, level);
986 // todo(jonahr): http://crbug.com/773861
987 // Behavior for now is to fallback to CPU readback implementation if the destination texture
988 // is a luminance format. The correct solution is to handle both source and destination in the
989 // luma workaround.
990 if (!destSRGB && !destLevelInfo.lumaWorkaround.enabled &&
991 nativegl::SupportsNativeRendering(functions, getType(), destLevelInfo.nativeInternalFormat))
992 {
993 bool copySucceeded = false;
994 ANGLE_TRY(blitter->copySubTexture(
995 context, sourceGL, sourceLevel, sourceComponentType, mTextureID, target, level,
996 destComponentType, sourceImageDesc.size, sourceArea, destOffset, needsLumaWorkaround,
997 sourceLevelInfo.sourceFormat, unpackFlipY, unpackPremultiplyAlpha,
998 unpackUnmultiplyAlpha, ©Succeeded));
999 if (copySucceeded)
1000 {
1001 return angle::Result::Continue;
1002 }
1003 }
1004
1005 // Fall back to CPU-readback
1006 return blitter->copySubTextureCPUReadback(
1007 context, sourceGL, sourceLevel, sourceFormatInfo.sizedInternalFormat, this, target, level,
1008 destFormat.format, destFormat.type, sourceImageDesc.size, sourceArea, destOffset,
1009 needsLumaWorkaround, sourceLevelInfo.sourceFormat, unpackFlipY, unpackPremultiplyAlpha,
1010 unpackUnmultiplyAlpha);
1011 }
1012
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)1013 angle::Result TextureGL::setStorage(const gl::Context *context,
1014 gl::TextureType type,
1015 size_t levels,
1016 GLenum internalFormat,
1017 const gl::Extents &size)
1018 {
1019 ContextGL *contextGL = GetImplAs<ContextGL>(context);
1020 const FunctionsGL *functions = GetFunctionsGL(context);
1021 StateManagerGL *stateManager = GetStateManagerGL(context);
1022 const angle::FeaturesGL &features = GetFeaturesGL(context);
1023
1024 nativegl::TexStorageFormat texStorageFormat =
1025 nativegl::GetTexStorageFormat(functions, features, internalFormat);
1026
1027 stateManager->bindTexture(getType(), mTextureID);
1028 if (nativegl::UseTexImage2D(getType()))
1029 {
1030 ASSERT(size.depth == 1);
1031 if (functions->texStorage2D)
1032 {
1033 ANGLE_GL_TRY_ALWAYS_CHECK(
1034 context,
1035 functions->texStorage2D(ToGLenum(type), static_cast<GLsizei>(levels),
1036 texStorageFormat.internalFormat, size.width, size.height));
1037 }
1038 else
1039 {
1040 // Make sure no pixel unpack buffer is bound
1041 stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
1042
1043 const gl::InternalFormat &internalFormatInfo =
1044 gl::GetSizedInternalFormatInfo(internalFormat);
1045
1046 // Internal format must be sized
1047 ASSERT(internalFormatInfo.sized);
1048
1049 for (size_t level = 0; level < levels; level++)
1050 {
1051 gl::Extents levelSize(std::max(size.width >> level, 1),
1052 std::max(size.height >> level, 1), 1);
1053
1054 if (getType() == gl::TextureType::_2D || getType() == gl::TextureType::Rectangle)
1055 {
1056 if (internalFormatInfo.compressed)
1057 {
1058 nativegl::CompressedTexSubImageFormat compressedTexImageFormat =
1059 nativegl::GetCompressedSubTexImageFormat(functions, features,
1060 internalFormat);
1061
1062 GLuint dataSize = 0;
1063 ANGLE_CHECK_GL_MATH(
1064 contextGL,
1065 internalFormatInfo.computeCompressedImageSize(levelSize, &dataSize));
1066 ANGLE_GL_TRY_ALWAYS_CHECK(
1067 context,
1068 functions->compressedTexImage2D(
1069 ToGLenum(type), static_cast<GLint>(level),
1070 compressedTexImageFormat.format, levelSize.width, levelSize.height,
1071 0, static_cast<GLsizei>(dataSize), nullptr));
1072 }
1073 else
1074 {
1075 nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
1076 functions, features, internalFormat, internalFormatInfo.format,
1077 internalFormatInfo.type);
1078
1079 ANGLE_GL_TRY_ALWAYS_CHECK(
1080 context,
1081 functions->texImage2D(ToGLenum(type), static_cast<GLint>(level),
1082 texImageFormat.internalFormat, levelSize.width,
1083 levelSize.height, 0, texImageFormat.format,
1084 texImageFormat.type, nullptr));
1085 }
1086 }
1087 else
1088 {
1089 ASSERT(getType() == gl::TextureType::CubeMap);
1090 for (gl::TextureTarget face : gl::AllCubeFaceTextureTargets())
1091 {
1092 if (internalFormatInfo.compressed)
1093 {
1094 nativegl::CompressedTexSubImageFormat compressedTexImageFormat =
1095 nativegl::GetCompressedSubTexImageFormat(functions, features,
1096 internalFormat);
1097
1098 GLuint dataSize = 0;
1099 ANGLE_CHECK_GL_MATH(contextGL,
1100 internalFormatInfo.computeCompressedImageSize(
1101 levelSize, &dataSize));
1102 ANGLE_GL_TRY_ALWAYS_CHECK(
1103 context,
1104 functions->compressedTexImage2D(
1105 ToGLenum(face), static_cast<GLint>(level),
1106 compressedTexImageFormat.format, levelSize.width,
1107 levelSize.height, 0, static_cast<GLsizei>(dataSize), nullptr));
1108 }
1109 else
1110 {
1111 nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
1112 functions, features, internalFormat, internalFormatInfo.format,
1113 internalFormatInfo.type);
1114
1115 ANGLE_GL_TRY_ALWAYS_CHECK(
1116 context, functions->texImage2D(
1117 ToGLenum(face), static_cast<GLint>(level),
1118 texImageFormat.internalFormat, levelSize.width,
1119 levelSize.height, 0, texImageFormat.format,
1120 texImageFormat.type, nullptr));
1121 }
1122 }
1123 }
1124 }
1125 }
1126 }
1127 else
1128 {
1129 ASSERT(nativegl::UseTexImage3D(getType()));
1130 const gl::InternalFormat &internalFormatInfo =
1131 gl::GetSizedInternalFormatInfo(internalFormat);
1132 const bool bypassTexStorage3D = type == gl::TextureType::_3D &&
1133 internalFormatInfo.compressed &&
1134 features.emulateImmutableCompressedTexture3D.enabled;
1135 if (functions->texStorage3D && !bypassTexStorage3D)
1136 {
1137 ANGLE_GL_TRY_ALWAYS_CHECK(
1138 context, functions->texStorage3D(ToGLenum(type), static_cast<GLsizei>(levels),
1139 texStorageFormat.internalFormat, size.width,
1140 size.height, size.depth));
1141 }
1142 else
1143 {
1144 // Make sure no pixel unpack buffer is bound
1145 stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
1146
1147 // Internal format must be sized
1148 ASSERT(internalFormatInfo.sized);
1149
1150 for (GLsizei i = 0; i < static_cast<GLsizei>(levels); i++)
1151 {
1152 gl::Extents levelSize(
1153 std::max(size.width >> i, 1), std::max(size.height >> i, 1),
1154 getType() == gl::TextureType::_3D ? std::max(size.depth >> i, 1) : size.depth);
1155
1156 if (internalFormatInfo.compressed)
1157 {
1158 nativegl::CompressedTexSubImageFormat compressedTexImageFormat =
1159 nativegl::GetCompressedSubTexImageFormat(functions, features,
1160 internalFormat);
1161
1162 GLuint dataSize = 0;
1163 ANGLE_CHECK_GL_MATH(contextGL, internalFormatInfo.computeCompressedImageSize(
1164 levelSize, &dataSize));
1165 ANGLE_GL_TRY_ALWAYS_CHECK(
1166 context, functions->compressedTexImage3D(
1167 ToGLenum(type), i, compressedTexImageFormat.format,
1168 levelSize.width, levelSize.height, levelSize.depth, 0,
1169 static_cast<GLsizei>(dataSize), nullptr));
1170 }
1171 else
1172 {
1173 nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
1174 functions, features, internalFormat, internalFormatInfo.format,
1175 internalFormatInfo.type);
1176
1177 ANGLE_GL_TRY_ALWAYS_CHECK(
1178 context,
1179 functions->texImage3D(ToGLenum(type), i, texImageFormat.internalFormat,
1180 levelSize.width, levelSize.height, levelSize.depth, 0,
1181 texImageFormat.format, texImageFormat.type, nullptr));
1182 }
1183 }
1184 }
1185 }
1186
1187 setLevelInfo(context, type, 0, levels,
1188 GetLevelInfo(features, internalFormat, texStorageFormat.internalFormat));
1189
1190 return angle::Result::Continue;
1191 }
1192
setImageExternal(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type)1193 angle::Result TextureGL::setImageExternal(const gl::Context *context,
1194 const gl::ImageIndex &index,
1195 GLenum internalFormat,
1196 const gl::Extents &size,
1197 GLenum format,
1198 GLenum type)
1199 {
1200 const FunctionsGL *functions = GetFunctionsGL(context);
1201 const angle::FeaturesGL &features = GetFeaturesGL(context);
1202
1203 gl::TextureTarget target = index.getTarget();
1204 size_t level = static_cast<size_t>(index.getLevelIndex());
1205 nativegl::TexImageFormat texImageFormat =
1206 nativegl::GetTexImageFormat(functions, features, internalFormat, format, type);
1207
1208 setLevelInfo(context, target, level, 1,
1209 GetLevelInfo(features, internalFormat, texImageFormat.internalFormat));
1210 return angle::Result::Continue;
1211 }
1212
setStorageMultisample(const gl::Context * context,gl::TextureType type,GLsizei samples,GLint internalformat,const gl::Extents & size,bool fixedSampleLocations)1213 angle::Result TextureGL::setStorageMultisample(const gl::Context *context,
1214 gl::TextureType type,
1215 GLsizei samples,
1216 GLint internalformat,
1217 const gl::Extents &size,
1218 bool fixedSampleLocations)
1219 {
1220 const FunctionsGL *functions = GetFunctionsGL(context);
1221 StateManagerGL *stateManager = GetStateManagerGL(context);
1222 const angle::FeaturesGL &features = GetFeaturesGL(context);
1223
1224 nativegl::TexStorageFormat texStorageFormat =
1225 nativegl::GetTexStorageFormat(functions, features, internalformat);
1226
1227 stateManager->bindTexture(getType(), mTextureID);
1228
1229 if (nativegl::UseTexImage2D(getType()))
1230 {
1231 ASSERT(size.depth == 1);
1232 if (functions->texStorage2DMultisample)
1233 {
1234 ANGLE_GL_TRY_ALWAYS_CHECK(
1235 context, functions->texStorage2DMultisample(
1236 ToGLenum(type), samples, texStorageFormat.internalFormat, size.width,
1237 size.height, gl::ConvertToGLBoolean(fixedSampleLocations)));
1238 }
1239 else
1240 {
1241 // texImage2DMultisample is similar to texStorage2DMultisample of es 3.1 core feature,
1242 // On macos and some old drivers which doesn't support OpenGL ES 3.1, the function can
1243 // be supported by ARB_texture_multisample or OpenGL 3.2 core feature.
1244 ANGLE_GL_TRY_ALWAYS_CHECK(
1245 context, functions->texImage2DMultisample(
1246 ToGLenum(type), samples, texStorageFormat.internalFormat, size.width,
1247 size.height, gl::ConvertToGLBoolean(fixedSampleLocations)));
1248 }
1249 }
1250 else
1251 {
1252 ASSERT(nativegl::UseTexImage3D(getType()));
1253 ANGLE_GL_TRY_ALWAYS_CHECK(
1254 context, functions->texStorage3DMultisample(
1255 ToGLenum(type), samples, texStorageFormat.internalFormat, size.width,
1256 size.height, size.depth, gl::ConvertToGLBoolean(fixedSampleLocations)));
1257 }
1258
1259 setLevelInfo(context, type, 0, 1,
1260 GetLevelInfo(features, internalformat, texStorageFormat.internalFormat));
1261
1262 return angle::Result::Continue;
1263 }
1264
setStorageExternalMemory(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size,gl::MemoryObject * memoryObject,GLuint64 offset,GLbitfield createFlags,GLbitfield usageFlags,const void * imageCreateInfoPNext)1265 angle::Result TextureGL::setStorageExternalMemory(const gl::Context *context,
1266 gl::TextureType type,
1267 size_t levels,
1268 GLenum internalFormat,
1269 const gl::Extents &size,
1270 gl::MemoryObject *memoryObject,
1271 GLuint64 offset,
1272 GLbitfield createFlags,
1273 GLbitfield usageFlags,
1274 const void *imageCreateInfoPNext)
1275 {
1276 // GL_ANGLE_external_objects_flags not supported.
1277 ASSERT(createFlags == 0);
1278 ASSERT(usageFlags == std::numeric_limits<uint32_t>::max());
1279 ASSERT(imageCreateInfoPNext == nullptr);
1280
1281 const FunctionsGL *functions = GetFunctionsGL(context);
1282 StateManagerGL *stateManager = GetStateManagerGL(context);
1283 const angle::FeaturesGL &features = GetFeaturesGL(context);
1284
1285 MemoryObjectGL *memoryObjectGL = GetImplAs<MemoryObjectGL>(memoryObject);
1286
1287 nativegl::TexStorageFormat texStorageFormat =
1288 nativegl::GetTexStorageFormat(functions, features, internalFormat);
1289
1290 stateManager->bindTexture(getType(), mTextureID);
1291 if (nativegl::UseTexImage2D(getType()))
1292 {
1293 ANGLE_GL_TRY_ALWAYS_CHECK(
1294 context,
1295 functions->texStorageMem2DEXT(ToGLenum(type), static_cast<GLsizei>(levels),
1296 texStorageFormat.internalFormat, size.width, size.height,
1297 memoryObjectGL->getMemoryObjectID(), offset));
1298 }
1299 else
1300 {
1301 ASSERT(nativegl::UseTexImage3D(getType()));
1302 ANGLE_GL_TRY_ALWAYS_CHECK(
1303 context,
1304 functions->texStorageMem3DEXT(ToGLenum(type), static_cast<GLsizei>(levels),
1305 texStorageFormat.internalFormat, size.width, size.height,
1306 size.depth, memoryObjectGL->getMemoryObjectID(), offset));
1307 }
1308
1309 setLevelInfo(context, type, 0, levels,
1310 GetLevelInfo(features, internalFormat, texStorageFormat.internalFormat));
1311
1312 return angle::Result::Continue;
1313 }
1314
setImageExternal(const gl::Context * context,gl::TextureType type,egl::Stream * stream,const egl::Stream::GLTextureDescription & desc)1315 angle::Result TextureGL::setImageExternal(const gl::Context *context,
1316 gl::TextureType type,
1317 egl::Stream *stream,
1318 const egl::Stream::GLTextureDescription &desc)
1319 {
1320 ANGLE_GL_UNREACHABLE(GetImplAs<ContextGL>(context));
1321 return angle::Result::Stop;
1322 }
1323
generateMipmap(const gl::Context * context)1324 angle::Result TextureGL::generateMipmap(const gl::Context *context)
1325 {
1326 const FunctionsGL *functions = GetFunctionsGL(context);
1327 StateManagerGL *stateManager = GetStateManagerGL(context);
1328 const angle::FeaturesGL &features = GetFeaturesGL(context);
1329
1330 const GLuint effectiveBaseLevel = mState.getEffectiveBaseLevel();
1331 const GLuint maxLevel = mState.getMipmapMaxLevel();
1332
1333 const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
1334 const gl::InternalFormat &baseLevelInternalFormat = *baseLevelDesc.format.info;
1335
1336 stateManager->bindTexture(getType(), mTextureID);
1337 if (baseLevelInternalFormat.colorEncoding == GL_SRGB &&
1338 features.encodeAndDecodeSRGBForGenerateMipmap.enabled && getType() == gl::TextureType::_2D)
1339 {
1340 nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
1341 functions, features, baseLevelInternalFormat.internalFormat,
1342 baseLevelInternalFormat.format, baseLevelInternalFormat.type);
1343
1344 // Manually allocate the mip levels of this texture if they don't exist
1345 GLuint levelCount = maxLevel - effectiveBaseLevel + 1;
1346 for (GLuint levelIdx = 1; levelIdx < levelCount; levelIdx++)
1347 {
1348 gl::Extents levelSize(std::max(baseLevelDesc.size.width >> levelIdx, 1),
1349 std::max(baseLevelDesc.size.height >> levelIdx, 1), 1);
1350
1351 const gl::ImageDesc &levelDesc =
1352 mState.getImageDesc(gl::TextureTarget::_2D, effectiveBaseLevel + levelIdx);
1353
1354 // Make sure no pixel unpack buffer is bound
1355 stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
1356
1357 if (levelDesc.size != levelSize || *levelDesc.format.info != baseLevelInternalFormat)
1358 {
1359 ANGLE_GL_TRY_ALWAYS_CHECK(
1360 context, functions->texImage2D(
1361 ToGLenum(getType()), effectiveBaseLevel + levelIdx,
1362 texImageFormat.internalFormat, levelSize.width, levelSize.height,
1363 0, texImageFormat.format, texImageFormat.type, nullptr));
1364 }
1365 }
1366
1367 // Use the blitter to generate the mips
1368 BlitGL *blitter = GetBlitGL(context);
1369 ANGLE_TRY(blitter->generateSRGBMipmap(context, this, effectiveBaseLevel, levelCount,
1370 baseLevelDesc.size));
1371 }
1372 else
1373 {
1374 ANGLE_GL_TRY_ALWAYS_CHECK(context, functions->generateMipmap(ToGLenum(getType())));
1375 }
1376
1377 setLevelInfo(context, getType(), effectiveBaseLevel, maxLevel - effectiveBaseLevel,
1378 getBaseLevelInfo());
1379
1380 return angle::Result::Continue;
1381 }
1382
bindTexImage(const gl::Context * context,egl::Surface * surface)1383 angle::Result TextureGL::bindTexImage(const gl::Context *context, egl::Surface *surface)
1384 {
1385 ASSERT(getType() == gl::TextureType::_2D || getType() == gl::TextureType::Rectangle);
1386
1387 StateManagerGL *stateManager = GetStateManagerGL(context);
1388
1389 // Make sure this texture is bound
1390 stateManager->bindTexture(getType(), mTextureID);
1391
1392 SurfaceGL *surfaceGL = GetImplAs<SurfaceGL>(surface);
1393
1394 const gl::Format &surfaceFormat = surface->getBindTexImageFormat();
1395 setLevelInfo(context, getType(), 0, 1,
1396 LevelInfoGL(surfaceFormat.info->format, surfaceFormat.info->internalFormat, false,
1397 LUMAWorkaroundGL(), surfaceGL->hasEmulatedAlphaChannel()));
1398 return angle::Result::Continue;
1399 }
1400
releaseTexImage(const gl::Context * context)1401 angle::Result TextureGL::releaseTexImage(const gl::Context *context)
1402 {
1403 ANGLE_TRY(recreateTexture(context));
1404 return angle::Result::Continue;
1405 }
1406
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)1407 angle::Result TextureGL::setEGLImageTarget(const gl::Context *context,
1408 gl::TextureType type,
1409 egl::Image *image)
1410 {
1411 const angle::FeaturesGL &features = GetFeaturesGL(context);
1412
1413 ImageGL *imageGL = GetImplAs<ImageGL>(image);
1414
1415 GLenum imageNativeInternalFormat = GL_NONE;
1416 ANGLE_TRY(imageGL->setTexture2D(context, type, this, &imageNativeInternalFormat));
1417
1418 setLevelInfo(
1419 context, type, 0, 1,
1420 GetLevelInfo(features, image->getFormat().info->internalFormat, imageNativeInternalFormat));
1421
1422 return angle::Result::Continue;
1423 }
1424
getNativeID() const1425 GLint TextureGL::getNativeID() const
1426 {
1427 return mTextureID;
1428 }
1429
syncState(const gl::Context * context,const gl::Texture::DirtyBits & dirtyBits,gl::Command source)1430 angle::Result TextureGL::syncState(const gl::Context *context,
1431 const gl::Texture::DirtyBits &dirtyBits,
1432 gl::Command source)
1433 {
1434 if (dirtyBits.none() && mLocalDirtyBits.none())
1435 {
1436 return angle::Result::Continue;
1437 }
1438
1439 const FunctionsGL *functions = GetFunctionsGL(context);
1440 StateManagerGL *stateManager = GetStateManagerGL(context);
1441
1442 stateManager->bindTexture(getType(), mTextureID);
1443
1444 gl::Texture::DirtyBits syncDirtyBits = dirtyBits | mLocalDirtyBits;
1445 if (dirtyBits[gl::Texture::DIRTY_BIT_BASE_LEVEL] || dirtyBits[gl::Texture::DIRTY_BIT_MAX_LEVEL])
1446 {
1447 // Don't know if the previous base level was using any workarounds, always re-sync the
1448 // workaround dirty bits
1449 syncDirtyBits |= GetLevelWorkaroundDirtyBits();
1450 }
1451 for (auto dirtyBit : syncDirtyBits)
1452 {
1453
1454 switch (dirtyBit)
1455 {
1456 case gl::Texture::DIRTY_BIT_MIN_FILTER:
1457 mAppliedSampler.setMinFilter(mState.getSamplerState().getMinFilter());
1458 ANGLE_GL_TRY(context, functions->texParameteri(
1459 nativegl::GetTextureBindingTarget(getType()),
1460 GL_TEXTURE_MIN_FILTER, mAppliedSampler.getMinFilter()));
1461 break;
1462 case gl::Texture::DIRTY_BIT_MAG_FILTER:
1463 mAppliedSampler.setMagFilter(mState.getSamplerState().getMagFilter());
1464 ANGLE_GL_TRY(context, functions->texParameteri(
1465 nativegl::GetTextureBindingTarget(getType()),
1466 GL_TEXTURE_MAG_FILTER, mAppliedSampler.getMagFilter()));
1467 break;
1468 case gl::Texture::DIRTY_BIT_WRAP_S:
1469 mAppliedSampler.setWrapS(mState.getSamplerState().getWrapS());
1470 ANGLE_GL_TRY(context, functions->texParameteri(
1471 nativegl::GetTextureBindingTarget(getType()),
1472 GL_TEXTURE_WRAP_S, mAppliedSampler.getWrapS()));
1473 break;
1474 case gl::Texture::DIRTY_BIT_WRAP_T:
1475 mAppliedSampler.setWrapT(mState.getSamplerState().getWrapT());
1476 ANGLE_GL_TRY(context, functions->texParameteri(
1477 nativegl::GetTextureBindingTarget(getType()),
1478 GL_TEXTURE_WRAP_T, mAppliedSampler.getWrapT()));
1479 break;
1480 case gl::Texture::DIRTY_BIT_WRAP_R:
1481 mAppliedSampler.setWrapR(mState.getSamplerState().getWrapR());
1482 ANGLE_GL_TRY(context, functions->texParameteri(
1483 nativegl::GetTextureBindingTarget(getType()),
1484 GL_TEXTURE_WRAP_R, mAppliedSampler.getWrapR()));
1485 break;
1486 case gl::Texture::DIRTY_BIT_MAX_ANISOTROPY:
1487 mAppliedSampler.setMaxAnisotropy(mState.getSamplerState().getMaxAnisotropy());
1488 ANGLE_GL_TRY(context,
1489 functions->texParameterf(nativegl::GetTextureBindingTarget(getType()),
1490 GL_TEXTURE_MAX_ANISOTROPY_EXT,
1491 mAppliedSampler.getMaxAnisotropy()));
1492 break;
1493 case gl::Texture::DIRTY_BIT_MIN_LOD:
1494 mAppliedSampler.setMinLod(mState.getSamplerState().getMinLod());
1495 ANGLE_GL_TRY(context, functions->texParameterf(
1496 nativegl::GetTextureBindingTarget(getType()),
1497 GL_TEXTURE_MIN_LOD, mAppliedSampler.getMinLod()));
1498 break;
1499 case gl::Texture::DIRTY_BIT_MAX_LOD:
1500 mAppliedSampler.setMaxLod(mState.getSamplerState().getMaxLod());
1501 ANGLE_GL_TRY(context, functions->texParameterf(
1502 nativegl::GetTextureBindingTarget(getType()),
1503 GL_TEXTURE_MAX_LOD, mAppliedSampler.getMaxLod()));
1504 break;
1505 case gl::Texture::DIRTY_BIT_COMPARE_MODE:
1506 mAppliedSampler.setCompareMode(mState.getSamplerState().getCompareMode());
1507 ANGLE_GL_TRY(context,
1508 functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1509 GL_TEXTURE_COMPARE_MODE,
1510 mAppliedSampler.getCompareMode()));
1511 break;
1512 case gl::Texture::DIRTY_BIT_COMPARE_FUNC:
1513 mAppliedSampler.setCompareFunc(mState.getSamplerState().getCompareFunc());
1514 ANGLE_GL_TRY(context,
1515 functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1516 GL_TEXTURE_COMPARE_FUNC,
1517 mAppliedSampler.getCompareFunc()));
1518 break;
1519 case gl::Texture::DIRTY_BIT_SRGB_DECODE:
1520 mAppliedSampler.setSRGBDecode(mState.getSamplerState().getSRGBDecode());
1521 ANGLE_GL_TRY(context,
1522 functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1523 GL_TEXTURE_SRGB_DECODE_EXT,
1524 mAppliedSampler.getSRGBDecode()));
1525 break;
1526 case gl::Texture::DIRTY_BIT_BORDER_COLOR:
1527 {
1528 const angle::ColorGeneric &borderColor(mState.getSamplerState().getBorderColor());
1529 mAppliedSampler.setBorderColor(borderColor);
1530 switch (borderColor.type)
1531 {
1532 case angle::ColorGeneric::Type::Float:
1533 ANGLE_GL_TRY(context,
1534 functions->texParameterfv(
1535 nativegl::GetTextureBindingTarget(getType()),
1536 GL_TEXTURE_BORDER_COLOR, &borderColor.colorF.red));
1537 break;
1538 case angle::ColorGeneric::Type::Int:
1539 ANGLE_GL_TRY(context,
1540 functions->texParameterIiv(
1541 nativegl::GetTextureBindingTarget(getType()),
1542 GL_TEXTURE_BORDER_COLOR, &borderColor.colorI.red));
1543 break;
1544 case angle::ColorGeneric::Type::UInt:
1545 ANGLE_GL_TRY(context,
1546 functions->texParameterIuiv(
1547 nativegl::GetTextureBindingTarget(getType()),
1548 GL_TEXTURE_BORDER_COLOR, &borderColor.colorUI.red));
1549 break;
1550 default:
1551 UNREACHABLE();
1552 break;
1553 }
1554 break;
1555 }
1556
1557 // Texture state
1558 case gl::Texture::DIRTY_BIT_SWIZZLE_RED:
1559 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_R,
1560 mState.getSwizzleState().swizzleRed,
1561 &mAppliedSwizzle.swizzleRed));
1562 break;
1563 case gl::Texture::DIRTY_BIT_SWIZZLE_GREEN:
1564 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_G,
1565 mState.getSwizzleState().swizzleGreen,
1566 &mAppliedSwizzle.swizzleGreen));
1567 break;
1568 case gl::Texture::DIRTY_BIT_SWIZZLE_BLUE:
1569 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_B,
1570 mState.getSwizzleState().swizzleBlue,
1571 &mAppliedSwizzle.swizzleBlue));
1572 break;
1573 case gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA:
1574 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_A,
1575 mState.getSwizzleState().swizzleAlpha,
1576 &mAppliedSwizzle.swizzleAlpha));
1577 break;
1578 case gl::Texture::DIRTY_BIT_BASE_LEVEL:
1579 mAppliedBaseLevel = mState.getEffectiveBaseLevel();
1580 ANGLE_GL_TRY(context,
1581 functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1582 GL_TEXTURE_BASE_LEVEL, mAppliedBaseLevel));
1583 break;
1584 case gl::Texture::DIRTY_BIT_MAX_LEVEL:
1585 mAppliedMaxLevel = mState.getEffectiveMaxLevel();
1586 ANGLE_GL_TRY(context,
1587 functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1588 GL_TEXTURE_MAX_LEVEL, mAppliedMaxLevel));
1589 break;
1590 case gl::Texture::DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE:
1591 {
1592 GLenum mDepthStencilTextureMode = mState.getDepthStencilTextureMode();
1593 ANGLE_GL_TRY(context, functions->texParameteri(
1594 nativegl::GetTextureBindingTarget(getType()),
1595 GL_DEPTH_STENCIL_TEXTURE_MODE, mDepthStencilTextureMode));
1596 break;
1597 }
1598 case gl::Texture::DIRTY_BIT_USAGE:
1599 break;
1600
1601 case gl::Texture::DIRTY_BIT_IMPLEMENTATION:
1602 // This special dirty bit is used to signal the front-end that the implementation
1603 // has local dirty bits. The real dirty bits are in mLocalDirty bits.
1604 break;
1605 case gl::Texture::DIRTY_BIT_BOUND_AS_IMAGE:
1606 case gl::Texture::DIRTY_BIT_BOUND_AS_ATTACHMENT:
1607 // Only used for Vulkan.
1608 break;
1609
1610 default:
1611 UNREACHABLE();
1612 }
1613 }
1614
1615 mAllModifiedDirtyBits |= syncDirtyBits;
1616 mLocalDirtyBits.reset();
1617 return angle::Result::Continue;
1618 }
1619
hasAnyDirtyBit() const1620 bool TextureGL::hasAnyDirtyBit() const
1621 {
1622 return mLocalDirtyBits.any();
1623 }
1624
setBaseLevel(const gl::Context * context,GLuint baseLevel)1625 angle::Result TextureGL::setBaseLevel(const gl::Context *context, GLuint baseLevel)
1626 {
1627 if (baseLevel != mAppliedBaseLevel)
1628 {
1629 const FunctionsGL *functions = GetFunctionsGL(context);
1630 StateManagerGL *stateManager = GetStateManagerGL(context);
1631
1632 mAppliedBaseLevel = baseLevel;
1633 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_BASE_LEVEL);
1634
1635 // Signal to the GL layer that the Impl has dirty bits.
1636 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1637
1638 stateManager->bindTexture(getType(), mTextureID);
1639 ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_BASE_LEVEL,
1640 baseLevel));
1641 }
1642 return angle::Result::Continue;
1643 }
1644
setMaxLevel(const gl::Context * context,GLuint maxLevel)1645 angle::Result TextureGL::setMaxLevel(const gl::Context *context, GLuint maxLevel)
1646 {
1647 if (maxLevel != mAppliedMaxLevel)
1648 {
1649 const FunctionsGL *functions = GetFunctionsGL(context);
1650 StateManagerGL *stateManager = GetStateManagerGL(context);
1651
1652 mAppliedMaxLevel = maxLevel;
1653 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MAX_LEVEL);
1654
1655 // Signal to the GL layer that the Impl has dirty bits.
1656 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1657
1658 stateManager->bindTexture(getType(), mTextureID);
1659 ANGLE_GL_TRY(context,
1660 functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MAX_LEVEL, maxLevel));
1661 }
1662 return angle::Result::Continue;
1663 }
1664
setMinFilter(const gl::Context * context,GLenum filter)1665 angle::Result TextureGL::setMinFilter(const gl::Context *context, GLenum filter)
1666 {
1667 if (mAppliedSampler.setMinFilter(filter))
1668 {
1669 const FunctionsGL *functions = GetFunctionsGL(context);
1670 StateManagerGL *stateManager = GetStateManagerGL(context);
1671
1672 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MIN_FILTER);
1673
1674 // Signal to the GL layer that the Impl has dirty bits.
1675 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1676
1677 stateManager->bindTexture(getType(), mTextureID);
1678 ANGLE_GL_TRY(context,
1679 functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MIN_FILTER, filter));
1680 }
1681 return angle::Result::Continue;
1682 }
setMagFilter(const gl::Context * context,GLenum filter)1683 angle::Result TextureGL::setMagFilter(const gl::Context *context, GLenum filter)
1684 {
1685 if (mAppliedSampler.setMagFilter(filter))
1686 {
1687 const FunctionsGL *functions = GetFunctionsGL(context);
1688 StateManagerGL *stateManager = GetStateManagerGL(context);
1689
1690 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MAG_FILTER);
1691
1692 // Signal to the GL layer that the Impl has dirty bits.
1693 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1694
1695 stateManager->bindTexture(getType(), mTextureID);
1696 ANGLE_GL_TRY(context,
1697 functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MAG_FILTER, filter));
1698 }
1699 return angle::Result::Continue;
1700 }
1701
setSwizzle(const gl::Context * context,GLint swizzle[4])1702 angle::Result TextureGL::setSwizzle(const gl::Context *context, GLint swizzle[4])
1703 {
1704 gl::SwizzleState resultingSwizzle =
1705 gl::SwizzleState(swizzle[0], swizzle[1], swizzle[2], swizzle[3]);
1706
1707 if (resultingSwizzle != mAppliedSwizzle)
1708 {
1709 const FunctionsGL *functions = GetFunctionsGL(context);
1710 StateManagerGL *stateManager = GetStateManagerGL(context);
1711
1712 mAppliedSwizzle = resultingSwizzle;
1713 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_RED);
1714 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_GREEN);
1715 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_BLUE);
1716 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA);
1717
1718 // Signal to the GL layer that the Impl has dirty bits.
1719 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1720
1721 stateManager->bindTexture(getType(), mTextureID);
1722 if (functions->standard == STANDARD_GL_ES)
1723 {
1724 ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1725 GL_TEXTURE_SWIZZLE_R, swizzle[0]));
1726 ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1727 GL_TEXTURE_SWIZZLE_G, swizzle[1]));
1728 ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1729 GL_TEXTURE_SWIZZLE_B, swizzle[2]));
1730 ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1731 GL_TEXTURE_SWIZZLE_A, swizzle[3]));
1732 }
1733 else
1734 {
1735 ANGLE_GL_TRY(context, functions->texParameteriv(ToGLenum(getType()),
1736 GL_TEXTURE_SWIZZLE_RGBA, swizzle));
1737 }
1738 }
1739 return angle::Result::Continue;
1740 }
1741
setBuffer(const gl::Context * context,GLenum internalFormat)1742 angle::Result TextureGL::setBuffer(const gl::Context *context, GLenum internalFormat)
1743 {
1744 const FunctionsGL *functions = GetFunctionsGL(context);
1745 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = mState.getBuffer();
1746 const gl::Buffer *buffer = bufferBinding.get();
1747 const GLintptr offset = bufferBinding.getOffset();
1748 const GLsizeiptr size = bufferBinding.getSize();
1749 const GLuint bufferID = buffer ? GetImplAs<BufferGL>(buffer)->getBufferID() : 0;
1750
1751 // If buffer is not bound, use texBuffer to unbind it. If size is 0, texBuffer was used to
1752 // create this binding, so use the same function. This will allow the implementation to take
1753 // the current size of the buffer on every draw/dispatch call even if the buffer size changes.
1754 if (buffer == nullptr || size == 0)
1755 {
1756 ANGLE_GL_TRY(context, functions->texBuffer(GL_TEXTURE_BUFFER, internalFormat, bufferID));
1757 }
1758 else
1759 {
1760 ANGLE_GL_TRY(context,
1761 functions->texBufferRange(GL_TEXTURE_BUFFER, internalFormat, bufferID, offset,
1762 GetBoundBufferAvailableSize(bufferBinding)));
1763 }
1764
1765 return angle::Result::Continue;
1766 }
1767
getNativeInternalFormat(const gl::ImageIndex & index) const1768 GLenum TextureGL::getNativeInternalFormat(const gl::ImageIndex &index) const
1769 {
1770 return getLevelInfo(index.getTarget(), index.getLevelIndex()).nativeInternalFormat;
1771 }
1772
hasEmulatedAlphaChannel(const gl::ImageIndex & index) const1773 bool TextureGL::hasEmulatedAlphaChannel(const gl::ImageIndex &index) const
1774 {
1775 return getLevelInfo(index.getTargetOrFirstCubeFace(), index.getLevelIndex())
1776 .emulatedAlphaChannel;
1777 }
1778
recreateTexture(const gl::Context * context)1779 angle::Result TextureGL::recreateTexture(const gl::Context *context)
1780 {
1781 const FunctionsGL *functions = GetFunctionsGL(context);
1782 StateManagerGL *stateManager = GetStateManagerGL(context);
1783
1784 stateManager->bindTexture(getType(), mTextureID);
1785 stateManager->deleteTexture(mTextureID);
1786
1787 functions->genTextures(1, &mTextureID);
1788 stateManager->bindTexture(getType(), mTextureID);
1789
1790 mLevelInfo.clear();
1791 mLevelInfo.resize(GetMaxLevelInfoCountForTextureType(getType()));
1792
1793 mAppliedSwizzle = gl::SwizzleState();
1794 mAppliedSampler = gl::SamplerState::CreateDefaultForTarget(getType());
1795
1796 mAppliedBaseLevel = 0;
1797 mAppliedBaseLevel = gl::kInitialMaxLevel;
1798
1799 mLocalDirtyBits = mAllModifiedDirtyBits;
1800
1801 onStateChange(angle::SubjectMessage::SubjectChanged);
1802
1803 return angle::Result::Continue;
1804 }
1805
syncTextureStateSwizzle(const gl::Context * context,const FunctionsGL * functions,GLenum name,GLenum value,GLenum * outValue)1806 angle::Result TextureGL::syncTextureStateSwizzle(const gl::Context *context,
1807 const FunctionsGL *functions,
1808 GLenum name,
1809 GLenum value,
1810 GLenum *outValue)
1811 {
1812 const LevelInfoGL &levelInfo = getBaseLevelInfo();
1813 GLenum resultSwizzle = value;
1814 if (levelInfo.lumaWorkaround.enabled)
1815 {
1816 switch (value)
1817 {
1818 case GL_RED:
1819 case GL_GREEN:
1820 case GL_BLUE:
1821 if (levelInfo.sourceFormat == GL_LUMINANCE ||
1822 levelInfo.sourceFormat == GL_LUMINANCE_ALPHA)
1823 {
1824 // Texture is backed by a RED or RG texture, point all color channels at the
1825 // red channel.
1826 ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RED ||
1827 levelInfo.lumaWorkaround.workaroundFormat == GL_RG);
1828 resultSwizzle = GL_RED;
1829 }
1830 else
1831 {
1832 ASSERT(levelInfo.sourceFormat == GL_ALPHA);
1833 // Color channels are not supposed to exist, make them always sample 0.
1834 resultSwizzle = GL_ZERO;
1835 }
1836 break;
1837
1838 case GL_ALPHA:
1839 if (levelInfo.sourceFormat == GL_LUMINANCE)
1840 {
1841 // Alpha channel is not supposed to exist, make it always sample 1.
1842 resultSwizzle = GL_ONE;
1843 }
1844 else if (levelInfo.sourceFormat == GL_ALPHA)
1845 {
1846 // Texture is backed by a RED texture, point the alpha channel at the red
1847 // channel.
1848 ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RED);
1849 resultSwizzle = GL_RED;
1850 }
1851 else
1852 {
1853 ASSERT(levelInfo.sourceFormat == GL_LUMINANCE_ALPHA);
1854 // Texture is backed by an RG texture, point the alpha channel at the green
1855 // channel.
1856 ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RG);
1857 resultSwizzle = GL_GREEN;
1858 }
1859 break;
1860
1861 case GL_ZERO:
1862 case GL_ONE:
1863 // Don't modify the swizzle state when requesting ZERO or ONE.
1864 resultSwizzle = value;
1865 break;
1866
1867 default:
1868 UNREACHABLE();
1869 break;
1870 }
1871 }
1872 else if (levelInfo.depthStencilWorkaround)
1873 {
1874 switch (value)
1875 {
1876 case GL_RED:
1877 // Don't modify the swizzle state when requesting the red channel.
1878 resultSwizzle = value;
1879 break;
1880
1881 case GL_GREEN:
1882 case GL_BLUE:
1883 if (context->getClientMajorVersion() <= 2)
1884 {
1885 // In OES_depth_texture/ARB_depth_texture, depth
1886 // textures are treated as luminance.
1887 resultSwizzle = GL_RED;
1888 }
1889 else
1890 {
1891 // In GLES 3.0, depth textures are treated as RED
1892 // textures, so green and blue should be 0.
1893 resultSwizzle = GL_ZERO;
1894 }
1895 break;
1896
1897 case GL_ALPHA:
1898 // Depth textures should sample 1 from the alpha channel.
1899 resultSwizzle = GL_ONE;
1900 break;
1901
1902 case GL_ZERO:
1903 case GL_ONE:
1904 // Don't modify the swizzle state when requesting ZERO or ONE.
1905 resultSwizzle = value;
1906 break;
1907
1908 default:
1909 UNREACHABLE();
1910 break;
1911 }
1912 }
1913 else if (levelInfo.emulatedAlphaChannel)
1914 {
1915 if (value == GL_ALPHA)
1916 {
1917 resultSwizzle = GL_ONE;
1918 }
1919 }
1920
1921 *outValue = resultSwizzle;
1922 ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()), name, resultSwizzle));
1923
1924 return angle::Result::Continue;
1925 }
1926
setLevelInfo(const gl::Context * context,gl::TextureTarget target,size_t level,size_t levelCount,const LevelInfoGL & levelInfo)1927 void TextureGL::setLevelInfo(const gl::Context *context,
1928 gl::TextureTarget target,
1929 size_t level,
1930 size_t levelCount,
1931 const LevelInfoGL &levelInfo)
1932 {
1933 ASSERT(levelCount > 0);
1934
1935 bool updateWorkarounds = levelInfo.depthStencilWorkaround || levelInfo.lumaWorkaround.enabled ||
1936 levelInfo.emulatedAlphaChannel;
1937
1938 for (size_t i = level; i < level + levelCount; i++)
1939 {
1940 size_t index = GetLevelInfoIndex(target, i);
1941 ASSERT(index < mLevelInfo.size());
1942 auto &curLevelInfo = mLevelInfo[index];
1943
1944 updateWorkarounds |= curLevelInfo.depthStencilWorkaround;
1945 updateWorkarounds |= curLevelInfo.lumaWorkaround.enabled;
1946 updateWorkarounds |= curLevelInfo.emulatedAlphaChannel;
1947
1948 curLevelInfo = levelInfo;
1949 }
1950
1951 if (updateWorkarounds)
1952 {
1953 mLocalDirtyBits |= GetLevelWorkaroundDirtyBits();
1954 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1955 }
1956 }
1957
setLevelInfo(const gl::Context * context,gl::TextureType type,size_t level,size_t levelCount,const LevelInfoGL & levelInfo)1958 void TextureGL::setLevelInfo(const gl::Context *context,
1959 gl::TextureType type,
1960 size_t level,
1961 size_t levelCount,
1962 const LevelInfoGL &levelInfo)
1963 {
1964 if (type == gl::TextureType::CubeMap)
1965 {
1966 for (gl::TextureTarget target : gl::AllCubeFaceTextureTargets())
1967 {
1968 setLevelInfo(context, target, level, levelCount, levelInfo);
1969 }
1970 }
1971 else
1972 {
1973 setLevelInfo(context, NonCubeTextureTypeToTarget(type), level, levelCount, levelInfo);
1974 }
1975 }
1976
getLevelInfo(gl::TextureTarget target,size_t level) const1977 const LevelInfoGL &TextureGL::getLevelInfo(gl::TextureTarget target, size_t level) const
1978 {
1979 return mLevelInfo[GetLevelInfoIndex(target, level)];
1980 }
1981
getBaseLevelInfo() const1982 const LevelInfoGL &TextureGL::getBaseLevelInfo() const
1983 {
1984 GLint effectiveBaseLevel = mState.getEffectiveBaseLevel();
1985 gl::TextureTarget target = getType() == gl::TextureType::CubeMap
1986 ? gl::kCubeMapTextureTargetMin
1987 : gl::NonCubeTextureTypeToTarget(getType());
1988 return getLevelInfo(target, effectiveBaseLevel);
1989 }
1990
getType() const1991 gl::TextureType TextureGL::getType() const
1992 {
1993 return mState.getType();
1994 }
1995
initializeContents(const gl::Context * context,const gl::ImageIndex & imageIndex)1996 angle::Result TextureGL::initializeContents(const gl::Context *context,
1997 const gl::ImageIndex &imageIndex)
1998 {
1999 ContextGL *contextGL = GetImplAs<ContextGL>(context);
2000 const FunctionsGL *functions = GetFunctionsGL(context);
2001 StateManagerGL *stateManager = GetStateManagerGL(context);
2002 const angle::FeaturesGL &features = GetFeaturesGL(context);
2003
2004 bool shouldUseClear = !nativegl::SupportsTexImage(getType());
2005 GLenum nativeInternalFormat =
2006 getLevelInfo(imageIndex.getTarget(), imageIndex.getLevelIndex()).nativeInternalFormat;
2007 if ((features.allowClearForRobustResourceInit.enabled || shouldUseClear) &&
2008 nativegl::SupportsNativeRendering(functions, mState.getType(), nativeInternalFormat))
2009 {
2010 BlitGL *blitter = GetBlitGL(context);
2011
2012 int levelDepth = mState.getImageDesc(imageIndex).size.depth;
2013
2014 bool clearSucceeded = false;
2015 ANGLE_TRY(blitter->clearRenderableTexture(context, this, nativeInternalFormat, levelDepth,
2016 imageIndex, &clearSucceeded));
2017 if (clearSucceeded)
2018 {
2019 return angle::Result::Continue;
2020 }
2021 }
2022
2023 // Either the texture is not renderable or was incomplete when clearing, fall back to a data
2024 // upload
2025 ASSERT(nativegl::SupportsTexImage(getType()));
2026 const gl::ImageDesc &desc = mState.getImageDesc(imageIndex);
2027 const gl::InternalFormat &internalFormatInfo = *desc.format.info;
2028
2029 gl::PixelUnpackState unpackState;
2030 unpackState.alignment = 1;
2031 ANGLE_TRY(stateManager->setPixelUnpackState(context, unpackState));
2032
2033 GLuint prevUnpackBuffer = stateManager->getBufferID(gl::BufferBinding::PixelUnpack);
2034 stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
2035
2036 stateManager->bindTexture(getType(), mTextureID);
2037 if (internalFormatInfo.compressed)
2038 {
2039 nativegl::CompressedTexSubImageFormat nativeSubImageFormat =
2040 nativegl::GetCompressedSubTexImageFormat(functions, features,
2041 internalFormatInfo.internalFormat);
2042
2043 GLuint imageSize = 0;
2044 ANGLE_CHECK_GL_MATH(contextGL,
2045 internalFormatInfo.computeCompressedImageSize(desc.size, &imageSize));
2046
2047 angle::MemoryBuffer *zero;
2048 ANGLE_CHECK_GL_ALLOC(contextGL, context->getZeroFilledBuffer(imageSize, &zero));
2049
2050 // WebGL spec requires that zero data is uploaded to compressed textures even if it might
2051 // not result in zero color data.
2052 if (nativegl::UseTexImage2D(getType()))
2053 {
2054 ANGLE_GL_TRY(context, functions->compressedTexSubImage2D(
2055 ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(),
2056 0, 0, desc.size.width, desc.size.height,
2057 nativeSubImageFormat.format, imageSize, zero->data()));
2058 }
2059 else
2060 {
2061 ASSERT(nativegl::UseTexImage3D(getType()));
2062 ANGLE_GL_TRY(context, functions->compressedTexSubImage3D(
2063 ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(),
2064 0, 0, 0, desc.size.width, desc.size.height, desc.size.depth,
2065 nativeSubImageFormat.format, imageSize, zero->data()));
2066 }
2067 }
2068 else
2069 {
2070 nativegl::TexSubImageFormat nativeSubImageFormat = nativegl::GetTexSubImageFormat(
2071 functions, features, internalFormatInfo.format, internalFormatInfo.type);
2072
2073 GLuint imageSize = 0;
2074 ANGLE_CHECK_GL_MATH(contextGL, internalFormatInfo.computePackUnpackEndByte(
2075 nativeSubImageFormat.type, desc.size, unpackState,
2076 nativegl::UseTexImage3D(getType()), &imageSize));
2077
2078 angle::MemoryBuffer *zero;
2079 ANGLE_CHECK_GL_ALLOC(contextGL, context->getZeroFilledBuffer(imageSize, &zero));
2080
2081 if (nativegl::UseTexImage2D(getType()))
2082 {
2083 if (features.uploadTextureDataInChunks.enabled)
2084 {
2085 gl::Box area(0, 0, 0, desc.size.width, desc.size.height, 1);
2086 ANGLE_TRY(setSubImageRowByRowWorkaround(
2087 context, imageIndex.getTarget(), imageIndex.getLevelIndex(), area,
2088 nativeSubImageFormat.format, nativeSubImageFormat.type, unpackState, nullptr,
2089 angle::FeaturesGL::kUploadTextureDataInChunksUploadSize, zero->data()));
2090 }
2091 else
2092 {
2093 ANGLE_GL_TRY(context,
2094 functions->texSubImage2D(
2095 ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(), 0, 0,
2096 desc.size.width, desc.size.height, nativeSubImageFormat.format,
2097 nativeSubImageFormat.type, zero->data()));
2098 }
2099 }
2100 else
2101 {
2102 ASSERT(nativegl::UseTexImage3D(getType()));
2103 ANGLE_GL_TRY(context,
2104 functions->texSubImage3D(
2105 ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(), 0, 0, 0,
2106 desc.size.width, desc.size.height, desc.size.depth,
2107 nativeSubImageFormat.format, nativeSubImageFormat.type, zero->data()));
2108 }
2109 }
2110
2111 // Reset the pixel unpack state. Because this call is made after synchronizing dirty bits in a
2112 // glTexImage call, we need to make sure that the texture data to be uploaded later has the
2113 // expected unpack state.
2114 ANGLE_TRY(stateManager->setPixelUnpackState(context, context->getState().getUnpackState()));
2115 stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, prevUnpackBuffer);
2116
2117 return angle::Result::Continue;
2118 }
2119
getRequiredExternalTextureImageUnits(const gl::Context * context)2120 GLint TextureGL::getRequiredExternalTextureImageUnits(const gl::Context *context)
2121 {
2122 const FunctionsGL *functions = GetFunctionsGL(context);
2123 StateManagerGL *stateManager = GetStateManagerGL(context);
2124
2125 ASSERT(getType() == gl::TextureType::External);
2126 stateManager->bindTexture(getType(), mTextureID);
2127
2128 GLint result = 0;
2129 functions->getTexParameteriv(ToGLenum(gl::NonCubeTextureTypeToTarget(getType())),
2130 GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES, &result);
2131 return result;
2132 }
2133
2134 } // namespace rx
2135