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