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 if (functions->texStorage3D)
1131 {
1132 ANGLE_GL_TRY_ALWAYS_CHECK(
1133 context, functions->texStorage3D(ToGLenum(type), static_cast<GLsizei>(levels),
1134 texStorageFormat.internalFormat, size.width,
1135 size.height, size.depth));
1136 }
1137 else
1138 {
1139 // Make sure no pixel unpack buffer is bound
1140 stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
1141
1142 const gl::InternalFormat &internalFormatInfo =
1143 gl::GetSizedInternalFormatInfo(internalFormat);
1144
1145 // Internal format must be sized
1146 ASSERT(internalFormatInfo.sized);
1147
1148 for (GLsizei i = 0; i < static_cast<GLsizei>(levels); i++)
1149 {
1150 gl::Extents levelSize(
1151 std::max(size.width >> i, 1), std::max(size.height >> i, 1),
1152 getType() == gl::TextureType::_3D ? std::max(size.depth >> i, 1) : size.depth);
1153
1154 if (internalFormatInfo.compressed)
1155 {
1156 nativegl::CompressedTexSubImageFormat compressedTexImageFormat =
1157 nativegl::GetCompressedSubTexImageFormat(functions, features,
1158 internalFormat);
1159
1160 GLuint dataSize = 0;
1161 ANGLE_CHECK_GL_MATH(contextGL, internalFormatInfo.computeCompressedImageSize(
1162 levelSize, &dataSize));
1163 ANGLE_GL_TRY_ALWAYS_CHECK(
1164 context, functions->compressedTexImage3D(
1165 ToGLenum(type), i, compressedTexImageFormat.format,
1166 levelSize.width, levelSize.height, levelSize.depth, 0,
1167 static_cast<GLsizei>(dataSize), nullptr));
1168 }
1169 else
1170 {
1171 nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
1172 functions, features, internalFormat, internalFormatInfo.format,
1173 internalFormatInfo.type);
1174
1175 ANGLE_GL_TRY_ALWAYS_CHECK(
1176 context,
1177 functions->texImage3D(ToGLenum(type), i, texImageFormat.internalFormat,
1178 levelSize.width, levelSize.height, levelSize.depth, 0,
1179 texImageFormat.format, texImageFormat.type, nullptr));
1180 }
1181 }
1182 }
1183 }
1184
1185 setLevelInfo(context, type, 0, levels,
1186 GetLevelInfo(features, internalFormat, texStorageFormat.internalFormat));
1187
1188 return angle::Result::Continue;
1189 }
1190
setImageExternal(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type)1191 angle::Result TextureGL::setImageExternal(const gl::Context *context,
1192 const gl::ImageIndex &index,
1193 GLenum internalFormat,
1194 const gl::Extents &size,
1195 GLenum format,
1196 GLenum type)
1197 {
1198 const FunctionsGL *functions = GetFunctionsGL(context);
1199 const angle::FeaturesGL &features = GetFeaturesGL(context);
1200
1201 gl::TextureTarget target = index.getTarget();
1202 size_t level = static_cast<size_t>(index.getLevelIndex());
1203 nativegl::TexImageFormat texImageFormat =
1204 nativegl::GetTexImageFormat(functions, features, internalFormat, format, type);
1205
1206 setLevelInfo(context, target, level, 1,
1207 GetLevelInfo(features, internalFormat, texImageFormat.internalFormat));
1208 return angle::Result::Continue;
1209 }
1210
setStorageMultisample(const gl::Context * context,gl::TextureType type,GLsizei samples,GLint internalformat,const gl::Extents & size,bool fixedSampleLocations)1211 angle::Result TextureGL::setStorageMultisample(const gl::Context *context,
1212 gl::TextureType type,
1213 GLsizei samples,
1214 GLint internalformat,
1215 const gl::Extents &size,
1216 bool fixedSampleLocations)
1217 {
1218 const FunctionsGL *functions = GetFunctionsGL(context);
1219 StateManagerGL *stateManager = GetStateManagerGL(context);
1220 const angle::FeaturesGL &features = GetFeaturesGL(context);
1221
1222 nativegl::TexStorageFormat texStorageFormat =
1223 nativegl::GetTexStorageFormat(functions, features, internalformat);
1224
1225 stateManager->bindTexture(getType(), mTextureID);
1226
1227 if (nativegl::UseTexImage2D(getType()))
1228 {
1229 ASSERT(size.depth == 1);
1230 if (functions->texStorage2DMultisample)
1231 {
1232 ANGLE_GL_TRY_ALWAYS_CHECK(
1233 context, functions->texStorage2DMultisample(
1234 ToGLenum(type), samples, texStorageFormat.internalFormat, size.width,
1235 size.height, gl::ConvertToGLBoolean(fixedSampleLocations)));
1236 }
1237 else
1238 {
1239 // texImage2DMultisample is similar to texStorage2DMultisample of es 3.1 core feature,
1240 // On macos and some old drivers which doesn't support OpenGL ES 3.1, the function can
1241 // be supported by ARB_texture_multisample or OpenGL 3.2 core feature.
1242 ANGLE_GL_TRY_ALWAYS_CHECK(
1243 context, functions->texImage2DMultisample(
1244 ToGLenum(type), samples, texStorageFormat.internalFormat, size.width,
1245 size.height, gl::ConvertToGLBoolean(fixedSampleLocations)));
1246 }
1247 }
1248 else
1249 {
1250 ASSERT(nativegl::UseTexImage3D(getType()));
1251 ANGLE_GL_TRY_ALWAYS_CHECK(
1252 context, functions->texStorage3DMultisample(
1253 ToGLenum(type), samples, texStorageFormat.internalFormat, size.width,
1254 size.height, size.depth, gl::ConvertToGLBoolean(fixedSampleLocations)));
1255 }
1256
1257 setLevelInfo(context, type, 0, 1,
1258 GetLevelInfo(features, internalformat, texStorageFormat.internalFormat));
1259
1260 return angle::Result::Continue;
1261 }
1262
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)1263 angle::Result TextureGL::setStorageExternalMemory(const gl::Context *context,
1264 gl::TextureType type,
1265 size_t levels,
1266 GLenum internalFormat,
1267 const gl::Extents &size,
1268 gl::MemoryObject *memoryObject,
1269 GLuint64 offset,
1270 GLbitfield createFlags,
1271 GLbitfield usageFlags)
1272 {
1273 // GL_ANGLE_external_objects_flags not supported.
1274 ASSERT(createFlags == 0);
1275 ASSERT(usageFlags == std::numeric_limits<uint32_t>::max());
1276
1277 const FunctionsGL *functions = GetFunctionsGL(context);
1278 StateManagerGL *stateManager = GetStateManagerGL(context);
1279 const angle::FeaturesGL &features = GetFeaturesGL(context);
1280
1281 MemoryObjectGL *memoryObjectGL = GetImplAs<MemoryObjectGL>(memoryObject);
1282
1283 nativegl::TexStorageFormat texStorageFormat =
1284 nativegl::GetTexStorageFormat(functions, features, internalFormat);
1285
1286 stateManager->bindTexture(getType(), mTextureID);
1287 if (nativegl::UseTexImage2D(getType()))
1288 {
1289 ANGLE_GL_TRY_ALWAYS_CHECK(
1290 context,
1291 functions->texStorageMem2DEXT(ToGLenum(type), static_cast<GLsizei>(levels),
1292 texStorageFormat.internalFormat, size.width, size.height,
1293 memoryObjectGL->getMemoryObjectID(), offset));
1294 }
1295 else
1296 {
1297 ASSERT(nativegl::UseTexImage3D(getType()));
1298 ANGLE_GL_TRY_ALWAYS_CHECK(
1299 context,
1300 functions->texStorageMem3DEXT(ToGLenum(type), static_cast<GLsizei>(levels),
1301 texStorageFormat.internalFormat, size.width, size.height,
1302 size.depth, memoryObjectGL->getMemoryObjectID(), offset));
1303 }
1304
1305 setLevelInfo(context, type, 0, levels,
1306 GetLevelInfo(features, internalFormat, texStorageFormat.internalFormat));
1307
1308 return angle::Result::Continue;
1309 }
1310
setImageExternal(const gl::Context * context,gl::TextureType type,egl::Stream * stream,const egl::Stream::GLTextureDescription & desc)1311 angle::Result TextureGL::setImageExternal(const gl::Context *context,
1312 gl::TextureType type,
1313 egl::Stream *stream,
1314 const egl::Stream::GLTextureDescription &desc)
1315 {
1316 ANGLE_GL_UNREACHABLE(GetImplAs<ContextGL>(context));
1317 return angle::Result::Stop;
1318 }
1319
generateMipmap(const gl::Context * context)1320 angle::Result TextureGL::generateMipmap(const gl::Context *context)
1321 {
1322 const FunctionsGL *functions = GetFunctionsGL(context);
1323 StateManagerGL *stateManager = GetStateManagerGL(context);
1324 const angle::FeaturesGL &features = GetFeaturesGL(context);
1325
1326 const GLuint effectiveBaseLevel = mState.getEffectiveBaseLevel();
1327 const GLuint maxLevel = mState.getMipmapMaxLevel();
1328
1329 const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
1330 const gl::InternalFormat &baseLevelInternalFormat = *baseLevelDesc.format.info;
1331
1332 stateManager->bindTexture(getType(), mTextureID);
1333 if (baseLevelInternalFormat.colorEncoding == GL_SRGB &&
1334 features.encodeAndDecodeSRGBForGenerateMipmap.enabled && getType() == gl::TextureType::_2D)
1335 {
1336 nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
1337 functions, features, baseLevelInternalFormat.internalFormat,
1338 baseLevelInternalFormat.format, baseLevelInternalFormat.type);
1339
1340 // Manually allocate the mip levels of this texture if they don't exist
1341 GLuint levelCount = maxLevel - effectiveBaseLevel + 1;
1342 for (GLuint levelIdx = 1; levelIdx < levelCount; levelIdx++)
1343 {
1344 gl::Extents levelSize(std::max(baseLevelDesc.size.width >> levelIdx, 1),
1345 std::max(baseLevelDesc.size.height >> levelIdx, 1), 1);
1346
1347 const gl::ImageDesc &levelDesc =
1348 mState.getImageDesc(gl::TextureTarget::_2D, effectiveBaseLevel + levelIdx);
1349
1350 // Make sure no pixel unpack buffer is bound
1351 stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
1352
1353 if (levelDesc.size != levelSize || *levelDesc.format.info != baseLevelInternalFormat)
1354 {
1355 ANGLE_GL_TRY_ALWAYS_CHECK(
1356 context, functions->texImage2D(
1357 ToGLenum(getType()), effectiveBaseLevel + levelIdx,
1358 texImageFormat.internalFormat, levelSize.width, levelSize.height,
1359 0, texImageFormat.format, texImageFormat.type, nullptr));
1360 }
1361 }
1362
1363 // Use the blitter to generate the mips
1364 BlitGL *blitter = GetBlitGL(context);
1365 ANGLE_TRY(blitter->generateSRGBMipmap(context, this, effectiveBaseLevel, levelCount,
1366 baseLevelDesc.size));
1367 }
1368 else
1369 {
1370 ANGLE_GL_TRY_ALWAYS_CHECK(context, functions->generateMipmap(ToGLenum(getType())));
1371 }
1372
1373 setLevelInfo(context, getType(), effectiveBaseLevel, maxLevel - effectiveBaseLevel,
1374 getBaseLevelInfo());
1375
1376 return angle::Result::Continue;
1377 }
1378
bindTexImage(const gl::Context * context,egl::Surface * surface)1379 angle::Result TextureGL::bindTexImage(const gl::Context *context, egl::Surface *surface)
1380 {
1381 ASSERT(getType() == gl::TextureType::_2D || getType() == gl::TextureType::Rectangle);
1382
1383 StateManagerGL *stateManager = GetStateManagerGL(context);
1384
1385 // Make sure this texture is bound
1386 stateManager->bindTexture(getType(), mTextureID);
1387
1388 SurfaceGL *surfaceGL = GetImplAs<SurfaceGL>(surface);
1389
1390 const gl::Format &surfaceFormat = surface->getBindTexImageFormat();
1391 setLevelInfo(context, getType(), 0, 1,
1392 LevelInfoGL(surfaceFormat.info->format, surfaceFormat.info->internalFormat, false,
1393 LUMAWorkaroundGL(), surfaceGL->hasEmulatedAlphaChannel()));
1394 return angle::Result::Continue;
1395 }
1396
releaseTexImage(const gl::Context * context)1397 angle::Result TextureGL::releaseTexImage(const gl::Context *context)
1398 {
1399 ANGLE_TRY(recreateTexture(context));
1400 return angle::Result::Continue;
1401 }
1402
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)1403 angle::Result TextureGL::setEGLImageTarget(const gl::Context *context,
1404 gl::TextureType type,
1405 egl::Image *image)
1406 {
1407 const angle::FeaturesGL &features = GetFeaturesGL(context);
1408
1409 ImageGL *imageGL = GetImplAs<ImageGL>(image);
1410
1411 GLenum imageNativeInternalFormat = GL_NONE;
1412 ANGLE_TRY(imageGL->setTexture2D(context, type, this, &imageNativeInternalFormat));
1413
1414 setLevelInfo(
1415 context, type, 0, 1,
1416 GetLevelInfo(features, image->getFormat().info->internalFormat, imageNativeInternalFormat));
1417
1418 return angle::Result::Continue;
1419 }
1420
getNativeID() const1421 GLint TextureGL::getNativeID() const
1422 {
1423 return mTextureID;
1424 }
1425
syncState(const gl::Context * context,const gl::Texture::DirtyBits & dirtyBits,gl::Command source)1426 angle::Result TextureGL::syncState(const gl::Context *context,
1427 const gl::Texture::DirtyBits &dirtyBits,
1428 gl::Command source)
1429 {
1430 if (dirtyBits.none() && mLocalDirtyBits.none())
1431 {
1432 return angle::Result::Continue;
1433 }
1434
1435 const FunctionsGL *functions = GetFunctionsGL(context);
1436 StateManagerGL *stateManager = GetStateManagerGL(context);
1437
1438 stateManager->bindTexture(getType(), mTextureID);
1439
1440 gl::Texture::DirtyBits syncDirtyBits = dirtyBits | mLocalDirtyBits;
1441 if (dirtyBits[gl::Texture::DIRTY_BIT_BASE_LEVEL] || dirtyBits[gl::Texture::DIRTY_BIT_MAX_LEVEL])
1442 {
1443 // Don't know if the previous base level was using any workarounds, always re-sync the
1444 // workaround dirty bits
1445 syncDirtyBits |= GetLevelWorkaroundDirtyBits();
1446 }
1447 for (auto dirtyBit : syncDirtyBits)
1448 {
1449
1450 switch (dirtyBit)
1451 {
1452 case gl::Texture::DIRTY_BIT_MIN_FILTER:
1453 mAppliedSampler.setMinFilter(mState.getSamplerState().getMinFilter());
1454 ANGLE_GL_TRY(context, functions->texParameteri(
1455 nativegl::GetTextureBindingTarget(getType()),
1456 GL_TEXTURE_MIN_FILTER, mAppliedSampler.getMinFilter()));
1457 break;
1458 case gl::Texture::DIRTY_BIT_MAG_FILTER:
1459 mAppliedSampler.setMagFilter(mState.getSamplerState().getMagFilter());
1460 ANGLE_GL_TRY(context, functions->texParameteri(
1461 nativegl::GetTextureBindingTarget(getType()),
1462 GL_TEXTURE_MAG_FILTER, mAppliedSampler.getMagFilter()));
1463 break;
1464 case gl::Texture::DIRTY_BIT_WRAP_S:
1465 mAppliedSampler.setWrapS(mState.getSamplerState().getWrapS());
1466 ANGLE_GL_TRY(context, functions->texParameteri(
1467 nativegl::GetTextureBindingTarget(getType()),
1468 GL_TEXTURE_WRAP_S, mAppliedSampler.getWrapS()));
1469 break;
1470 case gl::Texture::DIRTY_BIT_WRAP_T:
1471 mAppliedSampler.setWrapT(mState.getSamplerState().getWrapT());
1472 ANGLE_GL_TRY(context, functions->texParameteri(
1473 nativegl::GetTextureBindingTarget(getType()),
1474 GL_TEXTURE_WRAP_T, mAppliedSampler.getWrapT()));
1475 break;
1476 case gl::Texture::DIRTY_BIT_WRAP_R:
1477 mAppliedSampler.setWrapR(mState.getSamplerState().getWrapR());
1478 ANGLE_GL_TRY(context, functions->texParameteri(
1479 nativegl::GetTextureBindingTarget(getType()),
1480 GL_TEXTURE_WRAP_R, mAppliedSampler.getWrapR()));
1481 break;
1482 case gl::Texture::DIRTY_BIT_MAX_ANISOTROPY:
1483 mAppliedSampler.setMaxAnisotropy(mState.getSamplerState().getMaxAnisotropy());
1484 ANGLE_GL_TRY(context,
1485 functions->texParameterf(nativegl::GetTextureBindingTarget(getType()),
1486 GL_TEXTURE_MAX_ANISOTROPY_EXT,
1487 mAppliedSampler.getMaxAnisotropy()));
1488 break;
1489 case gl::Texture::DIRTY_BIT_MIN_LOD:
1490 mAppliedSampler.setMinLod(mState.getSamplerState().getMinLod());
1491 ANGLE_GL_TRY(context, functions->texParameterf(
1492 nativegl::GetTextureBindingTarget(getType()),
1493 GL_TEXTURE_MIN_LOD, mAppliedSampler.getMinLod()));
1494 break;
1495 case gl::Texture::DIRTY_BIT_MAX_LOD:
1496 mAppliedSampler.setMaxLod(mState.getSamplerState().getMaxLod());
1497 ANGLE_GL_TRY(context, functions->texParameterf(
1498 nativegl::GetTextureBindingTarget(getType()),
1499 GL_TEXTURE_MAX_LOD, mAppliedSampler.getMaxLod()));
1500 break;
1501 case gl::Texture::DIRTY_BIT_COMPARE_MODE:
1502 mAppliedSampler.setCompareMode(mState.getSamplerState().getCompareMode());
1503 ANGLE_GL_TRY(context,
1504 functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1505 GL_TEXTURE_COMPARE_MODE,
1506 mAppliedSampler.getCompareMode()));
1507 break;
1508 case gl::Texture::DIRTY_BIT_COMPARE_FUNC:
1509 mAppliedSampler.setCompareFunc(mState.getSamplerState().getCompareFunc());
1510 ANGLE_GL_TRY(context,
1511 functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1512 GL_TEXTURE_COMPARE_FUNC,
1513 mAppliedSampler.getCompareFunc()));
1514 break;
1515 case gl::Texture::DIRTY_BIT_SRGB_DECODE:
1516 mAppliedSampler.setSRGBDecode(mState.getSamplerState().getSRGBDecode());
1517 ANGLE_GL_TRY(context,
1518 functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1519 GL_TEXTURE_SRGB_DECODE_EXT,
1520 mAppliedSampler.getSRGBDecode()));
1521 break;
1522 case gl::Texture::DIRTY_BIT_BORDER_COLOR:
1523 {
1524 const angle::ColorGeneric &borderColor(mState.getSamplerState().getBorderColor());
1525 mAppliedSampler.setBorderColor(borderColor);
1526 switch (borderColor.type)
1527 {
1528 case angle::ColorGeneric::Type::Float:
1529 ANGLE_GL_TRY(context,
1530 functions->texParameterfv(
1531 nativegl::GetTextureBindingTarget(getType()),
1532 GL_TEXTURE_BORDER_COLOR, &borderColor.colorF.red));
1533 break;
1534 case angle::ColorGeneric::Type::Int:
1535 ANGLE_GL_TRY(context,
1536 functions->texParameterIiv(
1537 nativegl::GetTextureBindingTarget(getType()),
1538 GL_TEXTURE_BORDER_COLOR, &borderColor.colorI.red));
1539 break;
1540 case angle::ColorGeneric::Type::UInt:
1541 ANGLE_GL_TRY(context,
1542 functions->texParameterIuiv(
1543 nativegl::GetTextureBindingTarget(getType()),
1544 GL_TEXTURE_BORDER_COLOR, &borderColor.colorUI.red));
1545 break;
1546 default:
1547 UNREACHABLE();
1548 break;
1549 }
1550 break;
1551 }
1552
1553 // Texture state
1554 case gl::Texture::DIRTY_BIT_SWIZZLE_RED:
1555 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_R,
1556 mState.getSwizzleState().swizzleRed,
1557 &mAppliedSwizzle.swizzleRed));
1558 break;
1559 case gl::Texture::DIRTY_BIT_SWIZZLE_GREEN:
1560 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_G,
1561 mState.getSwizzleState().swizzleGreen,
1562 &mAppliedSwizzle.swizzleGreen));
1563 break;
1564 case gl::Texture::DIRTY_BIT_SWIZZLE_BLUE:
1565 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_B,
1566 mState.getSwizzleState().swizzleBlue,
1567 &mAppliedSwizzle.swizzleBlue));
1568 break;
1569 case gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA:
1570 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_A,
1571 mState.getSwizzleState().swizzleAlpha,
1572 &mAppliedSwizzle.swizzleAlpha));
1573 break;
1574 case gl::Texture::DIRTY_BIT_BASE_LEVEL:
1575 mAppliedBaseLevel = mState.getEffectiveBaseLevel();
1576 ANGLE_GL_TRY(context,
1577 functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1578 GL_TEXTURE_BASE_LEVEL, mAppliedBaseLevel));
1579 break;
1580 case gl::Texture::DIRTY_BIT_MAX_LEVEL:
1581 mAppliedMaxLevel = mState.getEffectiveMaxLevel();
1582 ANGLE_GL_TRY(context,
1583 functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1584 GL_TEXTURE_MAX_LEVEL, mAppliedMaxLevel));
1585 break;
1586 case gl::Texture::DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE:
1587 {
1588 GLenum mDepthStencilTextureMode = mState.getDepthStencilTextureMode();
1589 ANGLE_GL_TRY(context, functions->texParameteri(
1590 nativegl::GetTextureBindingTarget(getType()),
1591 GL_DEPTH_STENCIL_TEXTURE_MODE, mDepthStencilTextureMode));
1592 break;
1593 }
1594 case gl::Texture::DIRTY_BIT_USAGE:
1595 break;
1596 case gl::Texture::DIRTY_BIT_LABEL:
1597 break;
1598
1599 case gl::Texture::DIRTY_BIT_IMPLEMENTATION:
1600 // This special dirty bit is used to signal the front-end that the implementation
1601 // has local dirty bits. The real dirty bits are in mLocalDirty bits.
1602 break;
1603 case gl::Texture::DIRTY_BIT_BOUND_AS_IMAGE:
1604 // Only used for Vulkan.
1605 break;
1606
1607 default:
1608 UNREACHABLE();
1609 }
1610 }
1611
1612 mAllModifiedDirtyBits |= syncDirtyBits;
1613 mLocalDirtyBits.reset();
1614 return angle::Result::Continue;
1615 }
1616
hasAnyDirtyBit() const1617 bool TextureGL::hasAnyDirtyBit() const
1618 {
1619 return mLocalDirtyBits.any();
1620 }
1621
setBaseLevel(const gl::Context * context,GLuint baseLevel)1622 angle::Result TextureGL::setBaseLevel(const gl::Context *context, GLuint baseLevel)
1623 {
1624 if (baseLevel != mAppliedBaseLevel)
1625 {
1626 const FunctionsGL *functions = GetFunctionsGL(context);
1627 StateManagerGL *stateManager = GetStateManagerGL(context);
1628
1629 mAppliedBaseLevel = baseLevel;
1630 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_BASE_LEVEL);
1631
1632 // Signal to the GL layer that the Impl has dirty bits.
1633 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1634
1635 stateManager->bindTexture(getType(), mTextureID);
1636 ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_BASE_LEVEL,
1637 baseLevel));
1638 }
1639 return angle::Result::Continue;
1640 }
1641
setMaxLevel(const gl::Context * context,GLuint maxLevel)1642 angle::Result TextureGL::setMaxLevel(const gl::Context *context, GLuint maxLevel)
1643 {
1644 if (maxLevel != mAppliedMaxLevel)
1645 {
1646 const FunctionsGL *functions = GetFunctionsGL(context);
1647 StateManagerGL *stateManager = GetStateManagerGL(context);
1648
1649 mAppliedMaxLevel = maxLevel;
1650 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MAX_LEVEL);
1651
1652 // Signal to the GL layer that the Impl has dirty bits.
1653 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1654
1655 stateManager->bindTexture(getType(), mTextureID);
1656 ANGLE_GL_TRY(context,
1657 functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MAX_LEVEL, maxLevel));
1658 }
1659 return angle::Result::Continue;
1660 }
1661
setMinFilter(const gl::Context * context,GLenum filter)1662 angle::Result TextureGL::setMinFilter(const gl::Context *context, GLenum filter)
1663 {
1664 if (mAppliedSampler.setMinFilter(filter))
1665 {
1666 const FunctionsGL *functions = GetFunctionsGL(context);
1667 StateManagerGL *stateManager = GetStateManagerGL(context);
1668
1669 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MIN_FILTER);
1670
1671 // Signal to the GL layer that the Impl has dirty bits.
1672 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1673
1674 stateManager->bindTexture(getType(), mTextureID);
1675 ANGLE_GL_TRY(context,
1676 functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MIN_FILTER, filter));
1677 }
1678 return angle::Result::Continue;
1679 }
setMagFilter(const gl::Context * context,GLenum filter)1680 angle::Result TextureGL::setMagFilter(const gl::Context *context, GLenum filter)
1681 {
1682 if (mAppliedSampler.setMagFilter(filter))
1683 {
1684 const FunctionsGL *functions = GetFunctionsGL(context);
1685 StateManagerGL *stateManager = GetStateManagerGL(context);
1686
1687 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MAG_FILTER);
1688
1689 // Signal to the GL layer that the Impl has dirty bits.
1690 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1691
1692 stateManager->bindTexture(getType(), mTextureID);
1693 ANGLE_GL_TRY(context,
1694 functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MAG_FILTER, filter));
1695 }
1696 return angle::Result::Continue;
1697 }
1698
setSwizzle(const gl::Context * context,GLint swizzle[4])1699 angle::Result TextureGL::setSwizzle(const gl::Context *context, GLint swizzle[4])
1700 {
1701 gl::SwizzleState resultingSwizzle =
1702 gl::SwizzleState(swizzle[0], swizzle[1], swizzle[2], swizzle[3]);
1703
1704 if (resultingSwizzle != mAppliedSwizzle)
1705 {
1706 const FunctionsGL *functions = GetFunctionsGL(context);
1707 StateManagerGL *stateManager = GetStateManagerGL(context);
1708
1709 mAppliedSwizzle = resultingSwizzle;
1710 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_RED);
1711 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_GREEN);
1712 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_BLUE);
1713 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA);
1714
1715 // Signal to the GL layer that the Impl has dirty bits.
1716 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1717
1718 stateManager->bindTexture(getType(), mTextureID);
1719 if (functions->standard == STANDARD_GL_ES)
1720 {
1721 ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1722 GL_TEXTURE_SWIZZLE_R, swizzle[0]));
1723 ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1724 GL_TEXTURE_SWIZZLE_G, swizzle[1]));
1725 ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1726 GL_TEXTURE_SWIZZLE_B, swizzle[2]));
1727 ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1728 GL_TEXTURE_SWIZZLE_A, swizzle[3]));
1729 }
1730 else
1731 {
1732 ANGLE_GL_TRY(context, functions->texParameteriv(ToGLenum(getType()),
1733 GL_TEXTURE_SWIZZLE_RGBA, swizzle));
1734 }
1735 }
1736 return angle::Result::Continue;
1737 }
1738
setBuffer(const gl::Context * context,GLenum internalFormat)1739 angle::Result TextureGL::setBuffer(const gl::Context *context, GLenum internalFormat)
1740 {
1741 const FunctionsGL *functions = GetFunctionsGL(context);
1742 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = mState.getBuffer();
1743 const gl::Buffer *buffer = bufferBinding.get();
1744 const GLintptr offset = bufferBinding.getOffset();
1745 const GLsizeiptr size = bufferBinding.getSize();
1746 const GLuint bufferID = buffer ? GetImplAs<BufferGL>(buffer)->getBufferID() : 0;
1747
1748 // If buffer is not bound, use texBuffer to unbind it. If size is 0, texBuffer was used to
1749 // create this binding, so use the same function. This will allow the implementation to take
1750 // the current size of the buffer on every draw/dispatch call even if the buffer size changes.
1751 if (buffer == nullptr || size == 0)
1752 {
1753 ANGLE_GL_TRY(context, functions->texBuffer(GL_TEXTURE_BUFFER, internalFormat, bufferID));
1754 }
1755 else
1756 {
1757 ANGLE_GL_TRY(context,
1758 functions->texBufferRange(GL_TEXTURE_BUFFER, internalFormat, bufferID, offset,
1759 GetBoundBufferAvailableSize(bufferBinding)));
1760 }
1761
1762 return angle::Result::Continue;
1763 }
1764
getNativeInternalFormat(const gl::ImageIndex & index) const1765 GLenum TextureGL::getNativeInternalFormat(const gl::ImageIndex &index) const
1766 {
1767 return getLevelInfo(index.getTarget(), index.getLevelIndex()).nativeInternalFormat;
1768 }
1769
hasEmulatedAlphaChannel(const gl::ImageIndex & index) const1770 bool TextureGL::hasEmulatedAlphaChannel(const gl::ImageIndex &index) const
1771 {
1772 return getLevelInfo(index.getTargetOrFirstCubeFace(), index.getLevelIndex())
1773 .emulatedAlphaChannel;
1774 }
1775
recreateTexture(const gl::Context * context)1776 angle::Result TextureGL::recreateTexture(const gl::Context *context)
1777 {
1778 const FunctionsGL *functions = GetFunctionsGL(context);
1779 StateManagerGL *stateManager = GetStateManagerGL(context);
1780
1781 stateManager->bindTexture(getType(), mTextureID);
1782 stateManager->deleteTexture(mTextureID);
1783
1784 functions->genTextures(1, &mTextureID);
1785 stateManager->bindTexture(getType(), mTextureID);
1786
1787 mLevelInfo.clear();
1788 mLevelInfo.resize(GetMaxLevelInfoCountForTextureType(getType()));
1789
1790 mAppliedSwizzle = gl::SwizzleState();
1791 mAppliedSampler = gl::SamplerState::CreateDefaultForTarget(getType());
1792
1793 mAppliedBaseLevel = 0;
1794 mAppliedBaseLevel = gl::kInitialMaxLevel;
1795
1796 mLocalDirtyBits = mAllModifiedDirtyBits;
1797
1798 onStateChange(angle::SubjectMessage::SubjectChanged);
1799
1800 return angle::Result::Continue;
1801 }
1802
syncTextureStateSwizzle(const gl::Context * context,const FunctionsGL * functions,GLenum name,GLenum value,GLenum * outValue)1803 angle::Result TextureGL::syncTextureStateSwizzle(const gl::Context *context,
1804 const FunctionsGL *functions,
1805 GLenum name,
1806 GLenum value,
1807 GLenum *outValue)
1808 {
1809 const LevelInfoGL &levelInfo = getBaseLevelInfo();
1810 GLenum resultSwizzle = value;
1811 if (levelInfo.lumaWorkaround.enabled)
1812 {
1813 switch (value)
1814 {
1815 case GL_RED:
1816 case GL_GREEN:
1817 case GL_BLUE:
1818 if (levelInfo.sourceFormat == GL_LUMINANCE ||
1819 levelInfo.sourceFormat == GL_LUMINANCE_ALPHA)
1820 {
1821 // Texture is backed by a RED or RG texture, point all color channels at the
1822 // red channel.
1823 ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RED ||
1824 levelInfo.lumaWorkaround.workaroundFormat == GL_RG);
1825 resultSwizzle = GL_RED;
1826 }
1827 else
1828 {
1829 ASSERT(levelInfo.sourceFormat == GL_ALPHA);
1830 // Color channels are not supposed to exist, make them always sample 0.
1831 resultSwizzle = GL_ZERO;
1832 }
1833 break;
1834
1835 case GL_ALPHA:
1836 if (levelInfo.sourceFormat == GL_LUMINANCE)
1837 {
1838 // Alpha channel is not supposed to exist, make it always sample 1.
1839 resultSwizzle = GL_ONE;
1840 }
1841 else if (levelInfo.sourceFormat == GL_ALPHA)
1842 {
1843 // Texture is backed by a RED texture, point the alpha channel at the red
1844 // channel.
1845 ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RED);
1846 resultSwizzle = GL_RED;
1847 }
1848 else
1849 {
1850 ASSERT(levelInfo.sourceFormat == GL_LUMINANCE_ALPHA);
1851 // Texture is backed by an RG texture, point the alpha channel at the green
1852 // channel.
1853 ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RG);
1854 resultSwizzle = GL_GREEN;
1855 }
1856 break;
1857
1858 case GL_ZERO:
1859 case GL_ONE:
1860 // Don't modify the swizzle state when requesting ZERO or ONE.
1861 resultSwizzle = value;
1862 break;
1863
1864 default:
1865 UNREACHABLE();
1866 break;
1867 }
1868 }
1869 else if (levelInfo.depthStencilWorkaround)
1870 {
1871 switch (value)
1872 {
1873 case GL_RED:
1874 // Don't modify the swizzle state when requesting the red channel.
1875 resultSwizzle = value;
1876 break;
1877
1878 case GL_GREEN:
1879 case GL_BLUE:
1880 if (context->getClientMajorVersion() <= 2)
1881 {
1882 // In OES_depth_texture/ARB_depth_texture, depth
1883 // textures are treated as luminance.
1884 resultSwizzle = GL_RED;
1885 }
1886 else
1887 {
1888 // In GLES 3.0, depth textures are treated as RED
1889 // textures, so green and blue should be 0.
1890 resultSwizzle = GL_ZERO;
1891 }
1892 break;
1893
1894 case GL_ALPHA:
1895 // Depth textures should sample 1 from the alpha channel.
1896 resultSwizzle = GL_ONE;
1897 break;
1898
1899 case GL_ZERO:
1900 case GL_ONE:
1901 // Don't modify the swizzle state when requesting ZERO or ONE.
1902 resultSwizzle = value;
1903 break;
1904
1905 default:
1906 UNREACHABLE();
1907 break;
1908 }
1909 }
1910 else if (levelInfo.emulatedAlphaChannel)
1911 {
1912 if (value == GL_ALPHA)
1913 {
1914 resultSwizzle = GL_ONE;
1915 }
1916 }
1917
1918 *outValue = resultSwizzle;
1919 ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()), name, resultSwizzle));
1920
1921 return angle::Result::Continue;
1922 }
1923
setLevelInfo(const gl::Context * context,gl::TextureTarget target,size_t level,size_t levelCount,const LevelInfoGL & levelInfo)1924 void TextureGL::setLevelInfo(const gl::Context *context,
1925 gl::TextureTarget target,
1926 size_t level,
1927 size_t levelCount,
1928 const LevelInfoGL &levelInfo)
1929 {
1930 ASSERT(levelCount > 0);
1931
1932 bool updateWorkarounds = levelInfo.depthStencilWorkaround || levelInfo.lumaWorkaround.enabled ||
1933 levelInfo.emulatedAlphaChannel;
1934
1935 for (size_t i = level; i < level + levelCount; i++)
1936 {
1937 size_t index = GetLevelInfoIndex(target, i);
1938 ASSERT(index < mLevelInfo.size());
1939 auto &curLevelInfo = mLevelInfo[index];
1940
1941 updateWorkarounds |= curLevelInfo.depthStencilWorkaround;
1942 updateWorkarounds |= curLevelInfo.lumaWorkaround.enabled;
1943 updateWorkarounds |= curLevelInfo.emulatedAlphaChannel;
1944
1945 curLevelInfo = levelInfo;
1946 }
1947
1948 if (updateWorkarounds)
1949 {
1950 mLocalDirtyBits |= GetLevelWorkaroundDirtyBits();
1951 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1952 }
1953 }
1954
setLevelInfo(const gl::Context * context,gl::TextureType type,size_t level,size_t levelCount,const LevelInfoGL & levelInfo)1955 void TextureGL::setLevelInfo(const gl::Context *context,
1956 gl::TextureType type,
1957 size_t level,
1958 size_t levelCount,
1959 const LevelInfoGL &levelInfo)
1960 {
1961 if (type == gl::TextureType::CubeMap)
1962 {
1963 for (gl::TextureTarget target : gl::AllCubeFaceTextureTargets())
1964 {
1965 setLevelInfo(context, target, level, levelCount, levelInfo);
1966 }
1967 }
1968 else
1969 {
1970 setLevelInfo(context, NonCubeTextureTypeToTarget(type), level, levelCount, levelInfo);
1971 }
1972 }
1973
getLevelInfo(gl::TextureTarget target,size_t level) const1974 const LevelInfoGL &TextureGL::getLevelInfo(gl::TextureTarget target, size_t level) const
1975 {
1976 return mLevelInfo[GetLevelInfoIndex(target, level)];
1977 }
1978
getBaseLevelInfo() const1979 const LevelInfoGL &TextureGL::getBaseLevelInfo() const
1980 {
1981 GLint effectiveBaseLevel = mState.getEffectiveBaseLevel();
1982 gl::TextureTarget target = getType() == gl::TextureType::CubeMap
1983 ? gl::kCubeMapTextureTargetMin
1984 : gl::NonCubeTextureTypeToTarget(getType());
1985 return getLevelInfo(target, effectiveBaseLevel);
1986 }
1987
getType() const1988 gl::TextureType TextureGL::getType() const
1989 {
1990 return mState.getType();
1991 }
1992
initializeContents(const gl::Context * context,const gl::ImageIndex & imageIndex)1993 angle::Result TextureGL::initializeContents(const gl::Context *context,
1994 const gl::ImageIndex &imageIndex)
1995 {
1996 ContextGL *contextGL = GetImplAs<ContextGL>(context);
1997 const FunctionsGL *functions = GetFunctionsGL(context);
1998 StateManagerGL *stateManager = GetStateManagerGL(context);
1999 const angle::FeaturesGL &features = GetFeaturesGL(context);
2000
2001 bool shouldUseClear = !nativegl::SupportsTexImage(getType());
2002 GLenum nativeInternalFormat =
2003 getLevelInfo(imageIndex.getTarget(), imageIndex.getLevelIndex()).nativeInternalFormat;
2004 if ((features.allowClearForRobustResourceInit.enabled || shouldUseClear) &&
2005 nativegl::SupportsNativeRendering(functions, mState.getType(), nativeInternalFormat))
2006 {
2007 BlitGL *blitter = GetBlitGL(context);
2008
2009 int levelDepth = mState.getImageDesc(imageIndex).size.depth;
2010
2011 bool clearSucceeded = false;
2012 ANGLE_TRY(blitter->clearRenderableTexture(context, this, nativeInternalFormat, levelDepth,
2013 imageIndex, &clearSucceeded));
2014 if (clearSucceeded)
2015 {
2016 return angle::Result::Continue;
2017 }
2018 }
2019
2020 // Either the texture is not renderable or was incomplete when clearing, fall back to a data
2021 // upload
2022 ASSERT(nativegl::SupportsTexImage(getType()));
2023 const gl::ImageDesc &desc = mState.getImageDesc(imageIndex);
2024 const gl::InternalFormat &internalFormatInfo = *desc.format.info;
2025
2026 gl::PixelUnpackState unpackState;
2027 unpackState.alignment = 1;
2028 ANGLE_TRY(stateManager->setPixelUnpackState(context, unpackState));
2029
2030 GLuint prevUnpackBuffer = stateManager->getBufferID(gl::BufferBinding::PixelUnpack);
2031 stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
2032
2033 stateManager->bindTexture(getType(), mTextureID);
2034 if (internalFormatInfo.compressed)
2035 {
2036 nativegl::CompressedTexSubImageFormat nativeSubImageFormat =
2037 nativegl::GetCompressedSubTexImageFormat(functions, features,
2038 internalFormatInfo.internalFormat);
2039
2040 GLuint imageSize = 0;
2041 ANGLE_CHECK_GL_MATH(contextGL,
2042 internalFormatInfo.computeCompressedImageSize(desc.size, &imageSize));
2043
2044 angle::MemoryBuffer *zero;
2045 ANGLE_CHECK_GL_ALLOC(contextGL, context->getZeroFilledBuffer(imageSize, &zero));
2046
2047 // WebGL spec requires that zero data is uploaded to compressed textures even if it might
2048 // not result in zero color data.
2049 if (nativegl::UseTexImage2D(getType()))
2050 {
2051 ANGLE_GL_TRY(context, functions->compressedTexSubImage2D(
2052 ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(),
2053 0, 0, desc.size.width, desc.size.height,
2054 nativeSubImageFormat.format, imageSize, zero->data()));
2055 }
2056 else
2057 {
2058 ASSERT(nativegl::UseTexImage3D(getType()));
2059 ANGLE_GL_TRY(context, functions->compressedTexSubImage3D(
2060 ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(),
2061 0, 0, 0, desc.size.width, desc.size.height, desc.size.depth,
2062 nativeSubImageFormat.format, imageSize, zero->data()));
2063 }
2064 }
2065 else
2066 {
2067 nativegl::TexSubImageFormat nativeSubImageFormat = nativegl::GetTexSubImageFormat(
2068 functions, features, internalFormatInfo.format, internalFormatInfo.type);
2069
2070 GLuint imageSize = 0;
2071 ANGLE_CHECK_GL_MATH(contextGL, internalFormatInfo.computePackUnpackEndByte(
2072 nativeSubImageFormat.type, desc.size, unpackState,
2073 nativegl::UseTexImage3D(getType()), &imageSize));
2074
2075 angle::MemoryBuffer *zero;
2076 ANGLE_CHECK_GL_ALLOC(contextGL, context->getZeroFilledBuffer(imageSize, &zero));
2077
2078 if (nativegl::UseTexImage2D(getType()))
2079 {
2080 if (features.uploadTextureDataInChunks.enabled)
2081 {
2082 gl::Box area(0, 0, 0, desc.size.width, desc.size.height, 1);
2083 ANGLE_TRY(setSubImageRowByRowWorkaround(
2084 context, imageIndex.getTarget(), imageIndex.getLevelIndex(), area,
2085 nativeSubImageFormat.format, nativeSubImageFormat.type, unpackState, nullptr,
2086 angle::FeaturesGL::kUploadTextureDataInChunksUploadSize, zero->data()));
2087 }
2088 else
2089 {
2090 ANGLE_GL_TRY(context,
2091 functions->texSubImage2D(
2092 ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(), 0, 0,
2093 desc.size.width, desc.size.height, nativeSubImageFormat.format,
2094 nativeSubImageFormat.type, zero->data()));
2095 }
2096 }
2097 else
2098 {
2099 ASSERT(nativegl::UseTexImage3D(getType()));
2100 ANGLE_GL_TRY(context,
2101 functions->texSubImage3D(
2102 ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(), 0, 0, 0,
2103 desc.size.width, desc.size.height, desc.size.depth,
2104 nativeSubImageFormat.format, nativeSubImageFormat.type, zero->data()));
2105 }
2106 }
2107
2108 // Reset the pixel unpack state. Because this call is made after synchronizing dirty bits in a
2109 // glTexImage call, we need to make sure that the texture data to be uploaded later has the
2110 // expected unpack state.
2111 ANGLE_TRY(stateManager->setPixelUnpackState(context, context->getState().getUnpackState()));
2112 stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, prevUnpackBuffer);
2113
2114 return angle::Result::Continue;
2115 }
2116
getRequiredExternalTextureImageUnits(const gl::Context * context)2117 GLint TextureGL::getRequiredExternalTextureImageUnits(const gl::Context *context)
2118 {
2119 const FunctionsGL *functions = GetFunctionsGL(context);
2120 StateManagerGL *stateManager = GetStateManagerGL(context);
2121
2122 ASSERT(getType() == gl::TextureType::External);
2123 stateManager->bindTexture(getType(), mTextureID);
2124
2125 GLint result = 0;
2126 functions->getTexParameteriv(ToGLenum(gl::NonCubeTextureTypeToTarget(getType())),
2127 GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES, &result);
2128 return result;
2129 }
2130
2131 } // namespace rx
2132