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
bindTexImage(const gl::Context * context,egl::Surface * surface)1489 angle::Result TextureGL::bindTexImage(const gl::Context *context, egl::Surface *surface)
1490 {
1491 ASSERT(getType() == gl::TextureType::_2D || getType() == gl::TextureType::Rectangle);
1492
1493 StateManagerGL *stateManager = GetStateManagerGL(context);
1494
1495 // Make sure this texture is bound
1496 stateManager->bindTexture(getType(), mTextureID);
1497
1498 SurfaceGL *surfaceGL = GetImplAs<SurfaceGL>(surface);
1499
1500 const gl::Format &surfaceFormat = surface->getBindTexImageFormat();
1501 setLevelInfo(context, getType(), 0, 1,
1502 LevelInfoGL(surfaceFormat.info->format, surfaceFormat.info->internalFormat, false,
1503 LUMAWorkaroundGL(), surfaceGL->hasEmulatedAlphaChannel()));
1504 return angle::Result::Continue;
1505 }
1506
releaseTexImage(const gl::Context * context)1507 angle::Result TextureGL::releaseTexImage(const gl::Context *context)
1508 {
1509 ANGLE_TRY(recreateTexture(context));
1510 return angle::Result::Continue;
1511 }
1512
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)1513 angle::Result TextureGL::setEGLImageTarget(const gl::Context *context,
1514 gl::TextureType type,
1515 egl::Image *image)
1516 {
1517 const angle::FeaturesGL &features = GetFeaturesGL(context);
1518
1519 ImageGL *imageGL = GetImplAs<ImageGL>(image);
1520
1521 GLenum imageNativeInternalFormat = GL_NONE;
1522 ANGLE_TRY(imageGL->setTexture2D(context, type, this, &imageNativeInternalFormat));
1523
1524 const gl::InternalFormat &originalInternalFormatInfo = *image->getFormat().info;
1525
1526 setLevelInfo(context, type, 0, 1,
1527 GetLevelInfo(features, originalInternalFormatInfo, imageNativeInternalFormat));
1528
1529 return angle::Result::Continue;
1530 }
1531
getNativeID() const1532 GLint TextureGL::getNativeID() const
1533 {
1534 return mTextureID;
1535 }
1536
syncState(const gl::Context * context,const gl::Texture::DirtyBits & dirtyBits,gl::Command source)1537 angle::Result TextureGL::syncState(const gl::Context *context,
1538 const gl::Texture::DirtyBits &dirtyBits,
1539 gl::Command source)
1540 {
1541 if (dirtyBits.none() && mLocalDirtyBits.none())
1542 {
1543 return angle::Result::Continue;
1544 }
1545
1546 const FunctionsGL *functions = GetFunctionsGL(context);
1547 StateManagerGL *stateManager = GetStateManagerGL(context);
1548
1549 stateManager->bindTexture(getType(), mTextureID);
1550
1551 gl::Texture::DirtyBits syncDirtyBits = dirtyBits | mLocalDirtyBits;
1552 if (dirtyBits[gl::Texture::DIRTY_BIT_BASE_LEVEL] || dirtyBits[gl::Texture::DIRTY_BIT_MAX_LEVEL])
1553 {
1554 // Don't know if the previous base level was using any workarounds, always re-sync the
1555 // workaround dirty bits
1556 syncDirtyBits |= GetLevelWorkaroundDirtyBits();
1557
1558 // If the base level format has changed, depth stencil texture mode may need to be updated
1559 if (!mState.getImmutableFormat() && (context->getClientVersion() >= gl::ES_3_1 ||
1560 context->getExtensions().stencilTexturingANGLE))
1561 {
1562 syncDirtyBits.set(gl::Texture::DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE);
1563 }
1564
1565 // If the base level format has changed, border color may need to be updated
1566 if (!mState.getImmutableFormat() && (context->getClientVersion() >= gl::ES_3_2 ||
1567 context->getExtensions().textureBorderClampAny()))
1568 {
1569 syncDirtyBits.set(gl::Texture::DIRTY_BIT_BORDER_COLOR);
1570 }
1571 }
1572 for (auto dirtyBit : syncDirtyBits)
1573 {
1574
1575 switch (dirtyBit)
1576 {
1577 case gl::Texture::DIRTY_BIT_MIN_FILTER:
1578 if (mAppliedSampler.setMinFilter(mState.getSamplerState().getMinFilter()))
1579 {
1580 ANGLE_GL_TRY(context,
1581 functions->texParameteri(
1582 nativegl::GetTextureBindingTarget(getType()),
1583 GL_TEXTURE_MIN_FILTER, mAppliedSampler.getMinFilter()));
1584 }
1585 break;
1586 case gl::Texture::DIRTY_BIT_MAG_FILTER:
1587 if (mAppliedSampler.setMagFilter(mState.getSamplerState().getMagFilter()))
1588 {
1589 ANGLE_GL_TRY(context,
1590 functions->texParameteri(
1591 nativegl::GetTextureBindingTarget(getType()),
1592 GL_TEXTURE_MAG_FILTER, mAppliedSampler.getMagFilter()));
1593 }
1594 break;
1595 case gl::Texture::DIRTY_BIT_WRAP_S:
1596 if (mAppliedSampler.setWrapS(mState.getSamplerState().getWrapS()))
1597 {
1598 ANGLE_GL_TRY(context, functions->texParameteri(
1599 nativegl::GetTextureBindingTarget(getType()),
1600 GL_TEXTURE_WRAP_S, mAppliedSampler.getWrapS()));
1601 }
1602 break;
1603 case gl::Texture::DIRTY_BIT_WRAP_T:
1604 if (mAppliedSampler.setWrapT(mState.getSamplerState().getWrapT()))
1605 {
1606 ANGLE_GL_TRY(context, functions->texParameteri(
1607 nativegl::GetTextureBindingTarget(getType()),
1608 GL_TEXTURE_WRAP_T, mAppliedSampler.getWrapT()));
1609 }
1610 break;
1611 case gl::Texture::DIRTY_BIT_WRAP_R:
1612 if (mAppliedSampler.setWrapR(mState.getSamplerState().getWrapR()))
1613 {
1614 ANGLE_GL_TRY(context, functions->texParameteri(
1615 nativegl::GetTextureBindingTarget(getType()),
1616 GL_TEXTURE_WRAP_R, mAppliedSampler.getWrapR()));
1617 }
1618 break;
1619 case gl::Texture::DIRTY_BIT_MAX_ANISOTROPY:
1620 if (mAppliedSampler.setMaxAnisotropy(mState.getSamplerState().getMaxAnisotropy()))
1621 {
1622 ANGLE_GL_TRY(context, functions->texParameterf(
1623 nativegl::GetTextureBindingTarget(getType()),
1624 GL_TEXTURE_MAX_ANISOTROPY_EXT,
1625 mAppliedSampler.getMaxAnisotropy()));
1626 }
1627 break;
1628 case gl::Texture::DIRTY_BIT_MIN_LOD:
1629 if (mAppliedSampler.setMinLod(mState.getSamplerState().getMinLod()))
1630 {
1631 ANGLE_GL_TRY(context, functions->texParameterf(
1632 nativegl::GetTextureBindingTarget(getType()),
1633 GL_TEXTURE_MIN_LOD, mAppliedSampler.getMinLod()));
1634 }
1635 break;
1636 case gl::Texture::DIRTY_BIT_MAX_LOD:
1637 if (mAppliedSampler.setMaxLod(mState.getSamplerState().getMaxLod()))
1638 {
1639 ANGLE_GL_TRY(context, functions->texParameterf(
1640 nativegl::GetTextureBindingTarget(getType()),
1641 GL_TEXTURE_MAX_LOD, mAppliedSampler.getMaxLod()));
1642 }
1643 break;
1644 case gl::Texture::DIRTY_BIT_COMPARE_MODE:
1645 if (mAppliedSampler.setCompareMode(mState.getSamplerState().getCompareMode()))
1646 {
1647 ANGLE_GL_TRY(context,
1648 functions->texParameteri(
1649 nativegl::GetTextureBindingTarget(getType()),
1650 GL_TEXTURE_COMPARE_MODE, mAppliedSampler.getCompareMode()));
1651 }
1652 break;
1653 case gl::Texture::DIRTY_BIT_COMPARE_FUNC:
1654 if (mAppliedSampler.setCompareFunc(mState.getSamplerState().getCompareFunc()))
1655 {
1656 ANGLE_GL_TRY(context,
1657 functions->texParameteri(
1658 nativegl::GetTextureBindingTarget(getType()),
1659 GL_TEXTURE_COMPARE_FUNC, mAppliedSampler.getCompareFunc()));
1660 }
1661 break;
1662 case gl::Texture::DIRTY_BIT_SRGB_DECODE:
1663 if (mAppliedSampler.setSRGBDecode(mState.getSamplerState().getSRGBDecode()))
1664 {
1665 ANGLE_GL_TRY(context,
1666 functions->texParameteri(
1667 nativegl::GetTextureBindingTarget(getType()),
1668 GL_TEXTURE_SRGB_DECODE_EXT, mAppliedSampler.getSRGBDecode()));
1669 }
1670 break;
1671 case gl::Texture::DIRTY_BIT_BORDER_COLOR:
1672 {
1673 const LevelInfoGL &levelInfo = getBaseLevelInfo();
1674 angle::ColorGeneric borderColor = mState.getSamplerState().getBorderColor();
1675 // Formats that have workarounds must be present in FormatHasBorderColorWorkarounds.
1676 if (levelInfo.sourceFormat == GL_ALPHA)
1677 {
1678 if (levelInfo.lumaWorkaround.enabled)
1679 {
1680 ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RED);
1681 borderColor.colorF.red = borderColor.colorF.alpha;
1682 }
1683 else
1684 {
1685 // Some ES drivers treat ALPHA as swizzled RG, triplicating
1686 // border's red to RGB and sampling border's green as alpha.
1687 borderColor.colorF.red = 0.0f;
1688 borderColor.colorF.green = borderColor.colorF.alpha;
1689 }
1690 }
1691 else if (levelInfo.sourceFormat == GL_LUMINANCE_ALPHA)
1692 {
1693 if (levelInfo.lumaWorkaround.enabled)
1694 {
1695 ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RG);
1696 }
1697 // When using desktop GL, this format is emulated as swizzled RG.
1698 // Some ES drivers do the same without adjusting the border color.
1699 borderColor.colorF.green = borderColor.colorF.alpha;
1700 }
1701
1702 if (mAppliedSampler.setBorderColor(borderColor))
1703 {
1704 switch (borderColor.type)
1705 {
1706 case angle::ColorGeneric::Type::Float:
1707 ANGLE_GL_TRY(context,
1708 functions->texParameterfv(
1709 nativegl::GetTextureBindingTarget(getType()),
1710 GL_TEXTURE_BORDER_COLOR, &borderColor.colorF.red));
1711 break;
1712 case angle::ColorGeneric::Type::Int:
1713 ANGLE_GL_TRY(context,
1714 functions->texParameterIiv(
1715 nativegl::GetTextureBindingTarget(getType()),
1716 GL_TEXTURE_BORDER_COLOR, &borderColor.colorI.red));
1717 break;
1718 case angle::ColorGeneric::Type::UInt:
1719 ANGLE_GL_TRY(context,
1720 functions->texParameterIuiv(
1721 nativegl::GetTextureBindingTarget(getType()),
1722 GL_TEXTURE_BORDER_COLOR, &borderColor.colorUI.red));
1723 break;
1724 default:
1725 UNREACHABLE();
1726 break;
1727 }
1728 }
1729 break;
1730 }
1731
1732 // Texture state
1733 case gl::Texture::DIRTY_BIT_SWIZZLE_RED:
1734 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_R,
1735 mState.getSwizzleState().swizzleRed,
1736 &mAppliedSwizzle.swizzleRed));
1737 break;
1738 case gl::Texture::DIRTY_BIT_SWIZZLE_GREEN:
1739 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_G,
1740 mState.getSwizzleState().swizzleGreen,
1741 &mAppliedSwizzle.swizzleGreen));
1742 break;
1743 case gl::Texture::DIRTY_BIT_SWIZZLE_BLUE:
1744 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_B,
1745 mState.getSwizzleState().swizzleBlue,
1746 &mAppliedSwizzle.swizzleBlue));
1747 break;
1748 case gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA:
1749 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_A,
1750 mState.getSwizzleState().swizzleAlpha,
1751 &mAppliedSwizzle.swizzleAlpha));
1752 break;
1753 case gl::Texture::DIRTY_BIT_BASE_LEVEL:
1754 if (mAppliedBaseLevel != mState.getEffectiveBaseLevel())
1755 {
1756 mAppliedBaseLevel = mState.getEffectiveBaseLevel();
1757 ANGLE_GL_TRY(context, functions->texParameteri(
1758 nativegl::GetTextureBindingTarget(getType()),
1759 GL_TEXTURE_BASE_LEVEL, mAppliedBaseLevel));
1760 }
1761 break;
1762 case gl::Texture::DIRTY_BIT_MAX_LEVEL:
1763 if (mAppliedMaxLevel != mState.getEffectiveMaxLevel())
1764 {
1765 mAppliedMaxLevel = mState.getEffectiveMaxLevel();
1766 ANGLE_GL_TRY(context, functions->texParameteri(
1767 nativegl::GetTextureBindingTarget(getType()),
1768 GL_TEXTURE_MAX_LEVEL, mAppliedMaxLevel));
1769 }
1770 break;
1771 case gl::Texture::DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE:
1772 {
1773 ASSERT(context->getClientVersion() >= gl::ES_3_1 ||
1774 context->getExtensions().stencilTexturingANGLE);
1775
1776 // The DEPTH_STENCIL_TEXTURE_MODE state must affect only
1777 // DEPTH_STENCIL textures (OpenGL ES 3.2, Section 8.16).
1778 // Some drivers do not follow this rule and exhibit various side effects
1779 // when this mode is set to STENCIL_INDEX for textures of other formats.
1780 const GLenum mode = (getBaseLevelInfo().sourceFormat != GL_DEPTH_STENCIL)
1781 ? GL_DEPTH_COMPONENT
1782 : mState.getDepthStencilTextureMode();
1783
1784 if (mAppliedDepthStencilTextureMode != mode)
1785 {
1786 mAppliedDepthStencilTextureMode = mode;
1787 ANGLE_GL_TRY(context, functions->texParameteri(
1788 nativegl::GetTextureBindingTarget(getType()),
1789 GL_DEPTH_STENCIL_TEXTURE_MODE, mode));
1790 }
1791 break;
1792 }
1793 case gl::Texture::DIRTY_BIT_USAGE:
1794 case gl::Texture::DIRTY_BIT_RENDERABILITY_VALIDATION_ANGLE:
1795 break;
1796
1797 case gl::Texture::DIRTY_BIT_IMPLEMENTATION:
1798 // This special dirty bit is used to signal the front-end that the implementation
1799 // has local dirty bits. The real dirty bits are in mLocalDirty bits.
1800 break;
1801 case gl::Texture::DIRTY_BIT_BOUND_AS_IMAGE:
1802 case gl::Texture::DIRTY_BIT_BOUND_AS_ATTACHMENT:
1803 case gl::Texture::DIRTY_BIT_BOUND_TO_MSRTT_FRAMEBUFFER:
1804 // Only used for Vulkan.
1805 break;
1806
1807 default:
1808 UNREACHABLE();
1809 }
1810 }
1811
1812 mAllModifiedDirtyBits |= syncDirtyBits;
1813 mLocalDirtyBits.reset();
1814 return angle::Result::Continue;
1815 }
1816
hasAnyDirtyBit() const1817 bool TextureGL::hasAnyDirtyBit() const
1818 {
1819 return mLocalDirtyBits.any();
1820 }
1821
setBaseLevel(const gl::Context * context,GLuint baseLevel)1822 angle::Result TextureGL::setBaseLevel(const gl::Context *context, GLuint baseLevel)
1823 {
1824 if (baseLevel != mAppliedBaseLevel)
1825 {
1826 const FunctionsGL *functions = GetFunctionsGL(context);
1827 StateManagerGL *stateManager = GetStateManagerGL(context);
1828
1829 mAppliedBaseLevel = baseLevel;
1830 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_BASE_LEVEL);
1831
1832 // Signal to the GL layer that the Impl has dirty bits.
1833 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1834
1835 stateManager->bindTexture(getType(), mTextureID);
1836 ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_BASE_LEVEL,
1837 baseLevel));
1838 }
1839 return angle::Result::Continue;
1840 }
1841
setMaxLevel(const gl::Context * context,GLuint maxLevel)1842 angle::Result TextureGL::setMaxLevel(const gl::Context *context, GLuint maxLevel)
1843 {
1844 if (maxLevel != mAppliedMaxLevel)
1845 {
1846 const FunctionsGL *functions = GetFunctionsGL(context);
1847 StateManagerGL *stateManager = GetStateManagerGL(context);
1848
1849 mAppliedMaxLevel = maxLevel;
1850 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MAX_LEVEL);
1851
1852 // Signal to the GL layer that the Impl has dirty bits.
1853 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1854
1855 stateManager->bindTexture(getType(), mTextureID);
1856 ANGLE_GL_TRY(context,
1857 functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MAX_LEVEL, maxLevel));
1858 }
1859 return angle::Result::Continue;
1860 }
1861
setMinFilter(const gl::Context * context,GLenum filter)1862 angle::Result TextureGL::setMinFilter(const gl::Context *context, GLenum filter)
1863 {
1864 if (mAppliedSampler.setMinFilter(filter))
1865 {
1866 const FunctionsGL *functions = GetFunctionsGL(context);
1867 StateManagerGL *stateManager = GetStateManagerGL(context);
1868
1869 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MIN_FILTER);
1870
1871 // Signal to the GL layer that the Impl has dirty bits.
1872 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1873
1874 stateManager->bindTexture(getType(), mTextureID);
1875 ANGLE_GL_TRY(context,
1876 functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MIN_FILTER, filter));
1877 }
1878 return angle::Result::Continue;
1879 }
setMagFilter(const gl::Context * context,GLenum filter)1880 angle::Result TextureGL::setMagFilter(const gl::Context *context, GLenum filter)
1881 {
1882 if (mAppliedSampler.setMagFilter(filter))
1883 {
1884 const FunctionsGL *functions = GetFunctionsGL(context);
1885 StateManagerGL *stateManager = GetStateManagerGL(context);
1886
1887 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MAG_FILTER);
1888
1889 // Signal to the GL layer that the Impl has dirty bits.
1890 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1891
1892 stateManager->bindTexture(getType(), mTextureID);
1893 ANGLE_GL_TRY(context,
1894 functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MAG_FILTER, filter));
1895 }
1896 return angle::Result::Continue;
1897 }
1898
setSwizzle(const gl::Context * context,GLint swizzle[4])1899 angle::Result TextureGL::setSwizzle(const gl::Context *context, GLint swizzle[4])
1900 {
1901 gl::SwizzleState resultingSwizzle =
1902 gl::SwizzleState(swizzle[0], swizzle[1], swizzle[2], swizzle[3]);
1903
1904 if (resultingSwizzle != mAppliedSwizzle)
1905 {
1906 const FunctionsGL *functions = GetFunctionsGL(context);
1907 StateManagerGL *stateManager = GetStateManagerGL(context);
1908
1909 mAppliedSwizzle = resultingSwizzle;
1910 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_RED);
1911 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_GREEN);
1912 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_BLUE);
1913 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA);
1914
1915 // Signal to the GL layer that the Impl has dirty bits.
1916 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1917
1918 stateManager->bindTexture(getType(), mTextureID);
1919 if (functions->standard == STANDARD_GL_ES)
1920 {
1921 ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1922 GL_TEXTURE_SWIZZLE_R, swizzle[0]));
1923 ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1924 GL_TEXTURE_SWIZZLE_G, swizzle[1]));
1925 ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1926 GL_TEXTURE_SWIZZLE_B, swizzle[2]));
1927 ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1928 GL_TEXTURE_SWIZZLE_A, swizzle[3]));
1929 }
1930 else
1931 {
1932 ANGLE_GL_TRY(context, functions->texParameteriv(ToGLenum(getType()),
1933 GL_TEXTURE_SWIZZLE_RGBA, swizzle));
1934 }
1935 }
1936 return angle::Result::Continue;
1937 }
1938
setBuffer(const gl::Context * context,GLenum internalFormat)1939 angle::Result TextureGL::setBuffer(const gl::Context *context, GLenum internalFormat)
1940 {
1941 const FunctionsGL *functions = GetFunctionsGL(context);
1942 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = mState.getBuffer();
1943 const gl::Buffer *buffer = bufferBinding.get();
1944 const GLintptr offset = bufferBinding.getOffset();
1945 const GLsizeiptr size = bufferBinding.getSize();
1946 const GLuint bufferID = buffer ? GetImplAs<BufferGL>(buffer)->getBufferID() : 0;
1947
1948 // If buffer is not bound, use texBuffer to unbind it. If size is 0, texBuffer was used to
1949 // create this binding, so use the same function. This will allow the implementation to take
1950 // the current size of the buffer on every draw/dispatch call even if the buffer size changes.
1951 if (buffer == nullptr || size == 0)
1952 {
1953 ANGLE_GL_TRY(context, functions->texBuffer(GL_TEXTURE_BUFFER, internalFormat, bufferID));
1954 }
1955 else
1956 {
1957 ANGLE_GL_TRY(context,
1958 functions->texBufferRange(GL_TEXTURE_BUFFER, internalFormat, bufferID, offset,
1959 GetBoundBufferAvailableSize(bufferBinding)));
1960 }
1961
1962 return angle::Result::Continue;
1963 }
1964
getNativeInternalFormat(const gl::ImageIndex & index) const1965 GLenum TextureGL::getNativeInternalFormat(const gl::ImageIndex &index) const
1966 {
1967 return getLevelInfo(index.getTarget(), index.getLevelIndex()).nativeInternalFormat;
1968 }
1969
hasEmulatedAlphaChannel(const gl::ImageIndex & index) const1970 bool TextureGL::hasEmulatedAlphaChannel(const gl::ImageIndex &index) const
1971 {
1972 return getLevelInfo(index.getTargetOrFirstCubeFace(), index.getLevelIndex())
1973 .emulatedAlphaChannel;
1974 }
1975
recreateTexture(const gl::Context * context)1976 angle::Result TextureGL::recreateTexture(const gl::Context *context)
1977 {
1978 const FunctionsGL *functions = GetFunctionsGL(context);
1979 StateManagerGL *stateManager = GetStateManagerGL(context);
1980
1981 stateManager->bindTexture(getType(), mTextureID);
1982 stateManager->deleteTexture(mTextureID);
1983
1984 functions->genTextures(1, &mTextureID);
1985 stateManager->bindTexture(getType(), mTextureID);
1986
1987 mLevelInfo.clear();
1988 mLevelInfo.resize(GetMaxLevelInfoCountForTextureType(getType()));
1989
1990 mAppliedSwizzle = gl::SwizzleState();
1991 mAppliedSampler = gl::SamplerState::CreateDefaultForTarget(getType());
1992
1993 mAppliedBaseLevel = 0;
1994 mAppliedBaseLevel = gl::kInitialMaxLevel;
1995
1996 mLocalDirtyBits = mAllModifiedDirtyBits;
1997
1998 onStateChange(angle::SubjectMessage::SubjectChanged);
1999
2000 return angle::Result::Continue;
2001 }
2002
syncTextureStateSwizzle(const gl::Context * context,const FunctionsGL * functions,GLenum name,GLenum value,GLenum * currentlyAppliedValue)2003 angle::Result TextureGL::syncTextureStateSwizzle(const gl::Context *context,
2004 const FunctionsGL *functions,
2005 GLenum name,
2006 GLenum value,
2007 GLenum *currentlyAppliedValue)
2008 {
2009 const LevelInfoGL &levelInfo = getBaseLevelInfo();
2010 GLenum resultSwizzle = value;
2011 if (levelInfo.lumaWorkaround.enabled)
2012 {
2013 switch (value)
2014 {
2015 case GL_RED:
2016 case GL_GREEN:
2017 case GL_BLUE:
2018 if (levelInfo.sourceFormat == GL_LUMINANCE ||
2019 levelInfo.sourceFormat == GL_LUMINANCE_ALPHA)
2020 {
2021 // Texture is backed by a RED or RG texture, point all color channels at the
2022 // red channel.
2023 ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RED ||
2024 levelInfo.lumaWorkaround.workaroundFormat == GL_RG);
2025 resultSwizzle = GL_RED;
2026 }
2027 else
2028 {
2029 ASSERT(levelInfo.sourceFormat == GL_ALPHA);
2030 // Color channels are not supposed to exist, make them always sample 0.
2031 resultSwizzle = GL_ZERO;
2032 }
2033 break;
2034
2035 case GL_ALPHA:
2036 if (levelInfo.sourceFormat == GL_LUMINANCE)
2037 {
2038 // Alpha channel is not supposed to exist, make it always sample 1.
2039 resultSwizzle = GL_ONE;
2040 }
2041 else if (levelInfo.sourceFormat == GL_ALPHA)
2042 {
2043 // Texture is backed by a RED texture, point the alpha channel at the red
2044 // channel.
2045 ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RED);
2046 resultSwizzle = GL_RED;
2047 }
2048 else
2049 {
2050 ASSERT(levelInfo.sourceFormat == GL_LUMINANCE_ALPHA);
2051 // Texture is backed by an RG texture, point the alpha channel at the green
2052 // channel.
2053 ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RG);
2054 resultSwizzle = GL_GREEN;
2055 }
2056 break;
2057
2058 case GL_ZERO:
2059 case GL_ONE:
2060 // Don't modify the swizzle state when requesting ZERO or ONE.
2061 resultSwizzle = value;
2062 break;
2063
2064 default:
2065 UNREACHABLE();
2066 break;
2067 }
2068 }
2069 else if (levelInfo.depthStencilWorkaround)
2070 {
2071 switch (value)
2072 {
2073 case GL_RED:
2074 // Don't modify the swizzle state when requesting the red channel.
2075 resultSwizzle = value;
2076 break;
2077
2078 case GL_GREEN:
2079 case GL_BLUE:
2080 if (context->getClientMajorVersion() <= 2)
2081 {
2082 // In OES_depth_texture/ARB_depth_texture, depth
2083 // textures are treated as luminance.
2084 resultSwizzle = GL_RED;
2085 }
2086 else
2087 {
2088 // In GLES 3.0, depth textures are treated as RED
2089 // textures, so green and blue should be 0.
2090 resultSwizzle = GL_ZERO;
2091 }
2092 break;
2093
2094 case GL_ALPHA:
2095 // Depth textures should sample 1 from the alpha channel.
2096 resultSwizzle = GL_ONE;
2097 break;
2098
2099 case GL_ZERO:
2100 case GL_ONE:
2101 // Don't modify the swizzle state when requesting ZERO or ONE.
2102 resultSwizzle = value;
2103 break;
2104
2105 default:
2106 UNREACHABLE();
2107 break;
2108 }
2109 }
2110 else if (levelInfo.emulatedAlphaChannel)
2111 {
2112 if (value == GL_ALPHA)
2113 {
2114 resultSwizzle = GL_ONE;
2115 }
2116 }
2117
2118 if (*currentlyAppliedValue != resultSwizzle)
2119 {
2120 *currentlyAppliedValue = resultSwizzle;
2121 ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()), name, resultSwizzle));
2122 }
2123
2124 return angle::Result::Continue;
2125 }
2126
setLevelInfo(const gl::Context * context,gl::TextureTarget target,size_t level,size_t levelCount,const LevelInfoGL & levelInfo)2127 void TextureGL::setLevelInfo(const gl::Context *context,
2128 gl::TextureTarget target,
2129 size_t level,
2130 size_t levelCount,
2131 const LevelInfoGL &levelInfo)
2132 {
2133 ASSERT(levelCount > 0);
2134
2135 bool updateWorkarounds = levelInfo.depthStencilWorkaround || levelInfo.lumaWorkaround.enabled ||
2136 levelInfo.emulatedAlphaChannel;
2137
2138 bool updateDepthStencilTextureMode = false;
2139 const bool setToDepthStencil = levelInfo.sourceFormat == GL_DEPTH_STENCIL;
2140
2141 bool updateBorderColor = false;
2142 const bool targetFormatHasBorderColorWorkarounds =
2143 FormatHasBorderColorWorkarounds(levelInfo.sourceFormat);
2144
2145 for (size_t i = level; i < level + levelCount; i++)
2146 {
2147 size_t index = GetLevelInfoIndex(target, i);
2148 ASSERT(index < mLevelInfo.size());
2149 auto &curLevelInfo = mLevelInfo[index];
2150
2151 updateWorkarounds |= curLevelInfo.depthStencilWorkaround;
2152 updateWorkarounds |= curLevelInfo.lumaWorkaround.enabled;
2153 updateWorkarounds |= curLevelInfo.emulatedAlphaChannel;
2154
2155 // When redefining a level to or from DEPTH_STENCIL
2156 // format, ensure that the texture mode is synced.
2157 const bool setFromDepthStencil = curLevelInfo.sourceFormat == GL_DEPTH_STENCIL;
2158 if (setFromDepthStencil != setToDepthStencil)
2159 {
2160 updateDepthStencilTextureMode = true;
2161 }
2162
2163 // When redefining a level to or from a format that has border color workarounds,
2164 // ensure that the texture border color is synced.
2165 if (FormatHasBorderColorWorkarounds(curLevelInfo.sourceFormat) ||
2166 targetFormatHasBorderColorWorkarounds)
2167 {
2168 updateBorderColor = true;
2169 }
2170
2171 curLevelInfo = levelInfo;
2172 }
2173
2174 // Skip this step when unsupported
2175 updateDepthStencilTextureMode =
2176 updateDepthStencilTextureMode && (context->getClientVersion() >= gl::ES_3_1 ||
2177 context->getExtensions().stencilTexturingANGLE);
2178
2179 // Skip this step when unsupported
2180 updateBorderColor = updateBorderColor && (context->getClientVersion() >= gl::ES_3_2 ||
2181 context->getExtensions().textureBorderClampAny());
2182
2183 if (updateWorkarounds || updateDepthStencilTextureMode || updateBorderColor)
2184 {
2185 if (updateWorkarounds)
2186 {
2187 mLocalDirtyBits |= GetLevelWorkaroundDirtyBits();
2188 }
2189 if (updateDepthStencilTextureMode)
2190 {
2191 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE);
2192 }
2193 if (updateBorderColor)
2194 {
2195 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_BORDER_COLOR);
2196 }
2197 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
2198 }
2199 }
2200
setLevelInfo(const gl::Context * context,gl::TextureType type,size_t level,size_t levelCount,const LevelInfoGL & levelInfo)2201 void TextureGL::setLevelInfo(const gl::Context *context,
2202 gl::TextureType type,
2203 size_t level,
2204 size_t levelCount,
2205 const LevelInfoGL &levelInfo)
2206 {
2207 if (type == gl::TextureType::CubeMap)
2208 {
2209 for (gl::TextureTarget target : gl::AllCubeFaceTextureTargets())
2210 {
2211 setLevelInfo(context, target, level, levelCount, levelInfo);
2212 }
2213 }
2214 else
2215 {
2216 setLevelInfo(context, NonCubeTextureTypeToTarget(type), level, levelCount, levelInfo);
2217 }
2218 }
2219
getLevelInfo(gl::TextureTarget target,size_t level) const2220 const LevelInfoGL &TextureGL::getLevelInfo(gl::TextureTarget target, size_t level) const
2221 {
2222 return mLevelInfo[GetLevelInfoIndex(target, level)];
2223 }
2224
getBaseLevelInfo() const2225 const LevelInfoGL &TextureGL::getBaseLevelInfo() const
2226 {
2227 GLint effectiveBaseLevel = mState.getEffectiveBaseLevel();
2228 gl::TextureTarget target = getType() == gl::TextureType::CubeMap
2229 ? gl::kCubeMapTextureTargetMin
2230 : gl::NonCubeTextureTypeToTarget(getType());
2231 return getLevelInfo(target, effectiveBaseLevel);
2232 }
2233
getType() const2234 gl::TextureType TextureGL::getType() const
2235 {
2236 return mState.getType();
2237 }
2238
initializeContents(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex)2239 angle::Result TextureGL::initializeContents(const gl::Context *context,
2240 GLenum binding,
2241 const gl::ImageIndex &imageIndex)
2242 {
2243 ContextGL *contextGL = GetImplAs<ContextGL>(context);
2244 const FunctionsGL *functions = GetFunctionsGL(context);
2245 StateManagerGL *stateManager = GetStateManagerGL(context);
2246 const angle::FeaturesGL &features = GetFeaturesGL(context);
2247
2248 bool shouldUseClear = !nativegl::SupportsTexImage(getType());
2249 GLenum nativeInternalFormat =
2250 getLevelInfo(imageIndex.getTarget(), imageIndex.getLevelIndex()).nativeInternalFormat;
2251 if ((features.allowClearForRobustResourceInit.enabled || shouldUseClear) &&
2252 nativegl::SupportsNativeRendering(functions, mState.getType(), nativeInternalFormat))
2253 {
2254 BlitGL *blitter = GetBlitGL(context);
2255
2256 int levelDepth = mState.getImageDesc(imageIndex).size.depth;
2257
2258 bool clearSucceeded = false;
2259 ANGLE_TRY(blitter->clearRenderableTexture(context, this, nativeInternalFormat, levelDepth,
2260 imageIndex, &clearSucceeded));
2261 if (clearSucceeded)
2262 {
2263 contextGL->markWorkSubmitted();
2264 return angle::Result::Continue;
2265 }
2266 }
2267
2268 // Either the texture is not renderable or was incomplete when clearing, fall back to a data
2269 // upload
2270 ASSERT(nativegl::SupportsTexImage(getType()));
2271 const gl::ImageDesc &desc = mState.getImageDesc(imageIndex);
2272 const gl::InternalFormat &internalFormatInfo = *desc.format.info;
2273
2274 gl::PixelUnpackState unpackState;
2275 unpackState.alignment = 1;
2276 ANGLE_TRY(stateManager->setPixelUnpackState(context, unpackState));
2277
2278 GLuint prevUnpackBuffer = stateManager->getBufferID(gl::BufferBinding::PixelUnpack);
2279 stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
2280
2281 stateManager->bindTexture(getType(), mTextureID);
2282 if (internalFormatInfo.compressed)
2283 {
2284 nativegl::CompressedTexSubImageFormat nativeSubImageFormat =
2285 nativegl::GetCompressedSubTexImageFormat(functions, features,
2286 internalFormatInfo.internalFormat);
2287
2288 GLuint imageSize = 0;
2289 ANGLE_CHECK_GL_MATH(contextGL,
2290 internalFormatInfo.computeCompressedImageSize(desc.size, &imageSize));
2291
2292 angle::MemoryBuffer *zero;
2293 ANGLE_CHECK_GL_ALLOC(contextGL, context->getZeroFilledBuffer(imageSize, &zero));
2294
2295 // WebGL spec requires that zero data is uploaded to compressed textures even if it might
2296 // not result in zero color data.
2297 if (nativegl::UseTexImage2D(getType()))
2298 {
2299 ANGLE_GL_TRY(context, functions->compressedTexSubImage2D(
2300 ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(),
2301 0, 0, desc.size.width, desc.size.height,
2302 nativeSubImageFormat.format, imageSize, zero->data()));
2303 }
2304 else
2305 {
2306 ASSERT(nativegl::UseTexImage3D(getType()));
2307 ANGLE_GL_TRY(context, functions->compressedTexSubImage3D(
2308 ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(),
2309 0, 0, 0, desc.size.width, desc.size.height, desc.size.depth,
2310 nativeSubImageFormat.format, imageSize, zero->data()));
2311 }
2312 }
2313 else
2314 {
2315 nativegl::TexSubImageFormat nativeSubImageFormat = nativegl::GetTexSubImageFormat(
2316 functions, features, internalFormatInfo.format, internalFormatInfo.type);
2317
2318 GLuint imageSize = 0;
2319 ANGLE_CHECK_GL_MATH(contextGL, internalFormatInfo.computePackUnpackEndByte(
2320 nativeSubImageFormat.type, desc.size, unpackState,
2321 nativegl::UseTexImage3D(getType()), &imageSize));
2322
2323 angle::MemoryBuffer *zero;
2324 ANGLE_CHECK_GL_ALLOC(contextGL, context->getZeroFilledBuffer(imageSize, &zero));
2325
2326 if (nativegl::UseTexImage2D(getType()))
2327 {
2328 if (features.uploadTextureDataInChunks.enabled)
2329 {
2330 gl::Box area(0, 0, 0, desc.size.width, desc.size.height, 1);
2331 ANGLE_TRY(setSubImageRowByRowWorkaround(
2332 context, imageIndex.getTarget(), imageIndex.getLevelIndex(), area,
2333 nativeSubImageFormat.format, nativeSubImageFormat.type, unpackState, nullptr,
2334 kUploadTextureDataInChunksUploadSize, zero->data()));
2335 }
2336 else
2337 {
2338 ANGLE_GL_TRY(context,
2339 functions->texSubImage2D(
2340 ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(), 0, 0,
2341 desc.size.width, desc.size.height, nativeSubImageFormat.format,
2342 nativeSubImageFormat.type, zero->data()));
2343 }
2344 }
2345 else
2346 {
2347 ASSERT(nativegl::UseTexImage3D(getType()));
2348 ANGLE_GL_TRY(context,
2349 functions->texSubImage3D(
2350 ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(), 0, 0, 0,
2351 desc.size.width, desc.size.height, desc.size.depth,
2352 nativeSubImageFormat.format, nativeSubImageFormat.type, zero->data()));
2353 }
2354 }
2355
2356 // Reset the pixel unpack state. Because this call is made after synchronizing dirty bits in a
2357 // glTexImage call, we need to make sure that the texture data to be uploaded later has the
2358 // expected unpack state.
2359 ANGLE_TRY(stateManager->setPixelUnpackState(context, context->getState().getUnpackState()));
2360 stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, prevUnpackBuffer);
2361
2362 contextGL->markWorkSubmitted();
2363 return angle::Result::Continue;
2364 }
2365
getRequiredExternalTextureImageUnits(const gl::Context * context)2366 GLint TextureGL::getRequiredExternalTextureImageUnits(const gl::Context *context)
2367 {
2368 const FunctionsGL *functions = GetFunctionsGL(context);
2369 StateManagerGL *stateManager = GetStateManagerGL(context);
2370
2371 ASSERT(getType() == gl::TextureType::External);
2372 stateManager->bindTexture(getType(), mTextureID);
2373
2374 GLint result = 0;
2375 functions->getTexParameteriv(ToGLenum(gl::NonCubeTextureTypeToTarget(getType())),
2376 GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES, &result);
2377 return result;
2378 }
2379
2380 } // namespace rx
2381