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