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