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 (requiresInitialization)
717 {
718 ANGLE_GL_TRY(context, functions->copyTexSubImage2D(
719 ToGLenum(target), static_cast<GLint>(level), destOffset.x,
720 destOffset.y, clippedArea.x, clippedArea.y,
721 clippedArea.width, clippedArea.height));
722 }
723 else
724 {
725 ANGLE_GL_TRY_ALWAYS_CHECK(
726 context, functions->copyTexImage2D(ToGLenum(target), static_cast<GLint>(level),
727 copyTexImageFormat.internalFormat,
728 clippedArea.x, clippedArea.y,
729 clippedArea.width, clippedArea.height, 0));
730 }
731 }
732 setLevelInfo(context, target, level, 1, levelInfo);
733 }
734
735 if (features.flushBeforeDeleteTextureIfCopiedTo.enabled)
736 {
737 contextGL->setNeedsFlushBeforeDeleteTextures();
738 }
739
740 return angle::Result::Continue;
741 }
742
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)743 angle::Result TextureGL::copySubImage(const gl::Context *context,
744 const gl::ImageIndex &index,
745 const gl::Offset &destOffset,
746 const gl::Rectangle &sourceArea,
747 gl::Framebuffer *source)
748 {
749 const FunctionsGL *functions = GetFunctionsGL(context);
750 StateManagerGL *stateManager = GetStateManagerGL(context);
751 const angle::FeaturesGL &features = GetFeaturesGL(context);
752
753 gl::TextureTarget target = index.getTarget();
754 size_t level = static_cast<size_t>(index.getLevelIndex());
755 const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(source);
756
757 // Clip source area to framebuffer.
758 const gl::Extents fbSize = sourceFramebufferGL->getState().getReadAttachment()->getSize();
759 gl::Rectangle clippedArea;
760 if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
761 {
762 // nothing to do
763 return angle::Result::Continue;
764 }
765 gl::Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x,
766 destOffset.y + clippedArea.y - sourceArea.y, destOffset.z);
767
768 stateManager->bindTexture(getType(), mTextureID);
769 stateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, sourceFramebufferGL->getFramebufferID());
770
771 const LevelInfoGL &levelInfo = getLevelInfo(target, level);
772 if (levelInfo.lumaWorkaround.enabled)
773 {
774 BlitGL *blitter = GetBlitGL(context);
775 ANGLE_TRY(blitter->copySubImageToLUMAWorkaroundTexture(
776 context, mTextureID, getType(), target, levelInfo.sourceFormat, level, clippedOffset,
777 clippedArea, source));
778 }
779 else
780 {
781 if (nativegl::UseTexImage2D(getType()))
782 {
783 ASSERT(clippedOffset.z == 0);
784 ANGLE_GL_TRY(context, functions->copyTexSubImage2D(
785 ToGLenum(target), static_cast<GLint>(level), clippedOffset.x,
786 clippedOffset.y, clippedArea.x, clippedArea.y,
787 clippedArea.width, clippedArea.height));
788 }
789 else
790 {
791 ASSERT(nativegl::UseTexImage3D(getType()));
792 ANGLE_GL_TRY(context, functions->copyTexSubImage3D(
793 ToGLenum(target), static_cast<GLint>(level), clippedOffset.x,
794 clippedOffset.y, clippedOffset.z, clippedArea.x,
795 clippedArea.y, clippedArea.width, clippedArea.height));
796 }
797 }
798
799 if (features.flushBeforeDeleteTextureIfCopiedTo.enabled)
800 {
801 ContextGL *contextGL = GetImplAs<ContextGL>(context);
802 contextGL->setNeedsFlushBeforeDeleteTextures();
803 }
804
805 return angle::Result::Continue;
806 }
807
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)808 angle::Result TextureGL::copyTexture(const gl::Context *context,
809 const gl::ImageIndex &index,
810 GLenum internalFormat,
811 GLenum type,
812 size_t sourceLevel,
813 bool unpackFlipY,
814 bool unpackPremultiplyAlpha,
815 bool unpackUnmultiplyAlpha,
816 const gl::Texture *source)
817 {
818 gl::TextureTarget target = index.getTarget();
819 size_t level = static_cast<size_t>(index.getLevelIndex());
820 const TextureGL *sourceGL = GetImplAs<TextureGL>(source);
821 const gl::ImageDesc &sourceImageDesc =
822 sourceGL->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), sourceLevel);
823 gl::Rectangle sourceArea(0, 0, sourceImageDesc.size.width, sourceImageDesc.size.height);
824
825 ANGLE_TRY(reserveTexImageToBeFilled(context, target, level, internalFormat,
826 sourceImageDesc.size, gl::GetUnsizedFormat(internalFormat),
827 type));
828
829 const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
830 return copySubTextureHelper(context, target, level, gl::Offset(0, 0, 0), sourceLevel,
831 sourceArea, destFormatInfo, unpackFlipY, unpackPremultiplyAlpha,
832 unpackUnmultiplyAlpha, source);
833 }
834
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)835 angle::Result TextureGL::copySubTexture(const gl::Context *context,
836 const gl::ImageIndex &index,
837 const gl::Offset &destOffset,
838 size_t sourceLevel,
839 const gl::Box &sourceBox,
840 bool unpackFlipY,
841 bool unpackPremultiplyAlpha,
842 bool unpackUnmultiplyAlpha,
843 const gl::Texture *source)
844 {
845 gl::TextureTarget target = index.getTarget();
846 size_t level = static_cast<size_t>(index.getLevelIndex());
847 const gl::InternalFormat &destFormatInfo = *mState.getImageDesc(target, level).format.info;
848 return copySubTextureHelper(context, target, level, destOffset, sourceLevel, sourceBox.toRect(),
849 destFormatInfo, unpackFlipY, unpackPremultiplyAlpha,
850 unpackUnmultiplyAlpha, source);
851 }
852
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)853 angle::Result TextureGL::copySubTextureHelper(const gl::Context *context,
854 gl::TextureTarget target,
855 size_t level,
856 const gl::Offset &destOffset,
857 size_t sourceLevel,
858 const gl::Rectangle &sourceArea,
859 const gl::InternalFormat &destFormat,
860 bool unpackFlipY,
861 bool unpackPremultiplyAlpha,
862 bool unpackUnmultiplyAlpha,
863 const gl::Texture *source)
864 {
865 const FunctionsGL *functions = GetFunctionsGL(context);
866 const angle::FeaturesGL &features = GetFeaturesGL(context);
867 BlitGL *blitter = GetBlitGL(context);
868
869 TextureGL *sourceGL = GetImplAs<TextureGL>(source);
870 const gl::ImageDesc &sourceImageDesc =
871 sourceGL->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), sourceLevel);
872
873 if (features.flushBeforeDeleteTextureIfCopiedTo.enabled)
874 {
875 // Conservatively indicate that this workaround is necessary. Not clear
876 // if it is on this code path, but added for symmetry.
877 ContextGL *contextGL = GetImplAs<ContextGL>(context);
878 contextGL->setNeedsFlushBeforeDeleteTextures();
879 }
880
881 // Check is this is a simple copySubTexture that can be done with a copyTexSubImage
882 ASSERT(sourceGL->getType() == gl::TextureType::_2D ||
883 source->getType() == gl::TextureType::External ||
884 source->getType() == gl::TextureType::Rectangle);
885 const LevelInfoGL &sourceLevelInfo =
886 sourceGL->getLevelInfo(NonCubeTextureTypeToTarget(source->getType()), sourceLevel);
887 bool needsLumaWorkaround = sourceLevelInfo.lumaWorkaround.enabled;
888
889 const gl::InternalFormat &sourceFormatInfo = *sourceImageDesc.format.info;
890 GLenum sourceFormat = sourceFormatInfo.format;
891 bool sourceFormatContainSupersetOfDestFormat =
892 (sourceFormat == destFormat.format && sourceFormat != GL_BGRA_EXT) ||
893 (sourceFormat == GL_RGBA && destFormat.format == GL_RGB);
894
895 GLenum sourceComponentType = sourceFormatInfo.componentType;
896 GLenum destComponentType = destFormat.componentType;
897 bool destSRGB = destFormat.colorEncoding == GL_SRGB;
898 if (!unpackFlipY && unpackPremultiplyAlpha == unpackUnmultiplyAlpha && !needsLumaWorkaround &&
899 sourceFormatContainSupersetOfDestFormat && sourceComponentType == destComponentType &&
900 !destSRGB && sourceGL->getType() == gl::TextureType::_2D)
901 {
902 bool copySucceeded = false;
903 ANGLE_TRY(blitter->copyTexSubImage(context, sourceGL, sourceLevel, this, target, level,
904 sourceArea, destOffset, ©Succeeded));
905 if (copySucceeded)
906 {
907 return angle::Result::Continue;
908 }
909 }
910
911 // Check if the destination is renderable and copy on the GPU
912 const LevelInfoGL &destLevelInfo = getLevelInfo(target, level);
913 // todo(jonahr): http://crbug.com/773861
914 // Behavior for now is to fallback to CPU readback implementation if the destination texture
915 // is a luminance format. The correct solution is to handle both source and destination in the
916 // luma workaround.
917 if (!destSRGB && !destLevelInfo.lumaWorkaround.enabled &&
918 nativegl::SupportsNativeRendering(functions, getType(), destLevelInfo.nativeInternalFormat))
919 {
920 bool copySucceeded = false;
921 ANGLE_TRY(blitter->copySubTexture(
922 context, sourceGL, sourceLevel, sourceComponentType, mTextureID, target, level,
923 destComponentType, sourceImageDesc.size, sourceArea, destOffset, needsLumaWorkaround,
924 sourceLevelInfo.sourceFormat, unpackFlipY, unpackPremultiplyAlpha,
925 unpackUnmultiplyAlpha, ©Succeeded));
926 if (copySucceeded)
927 {
928 return angle::Result::Continue;
929 }
930 }
931
932 // Fall back to CPU-readback
933 return blitter->copySubTextureCPUReadback(
934 context, sourceGL, sourceLevel, sourceFormatInfo.sizedInternalFormat, this, target, level,
935 destFormat.format, destFormat.type, sourceImageDesc.size, sourceArea, destOffset,
936 needsLumaWorkaround, sourceLevelInfo.sourceFormat, unpackFlipY, unpackPremultiplyAlpha,
937 unpackUnmultiplyAlpha);
938 }
939
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)940 angle::Result TextureGL::setStorage(const gl::Context *context,
941 gl::TextureType type,
942 size_t levels,
943 GLenum internalFormat,
944 const gl::Extents &size)
945 {
946 ContextGL *contextGL = GetImplAs<ContextGL>(context);
947 const FunctionsGL *functions = GetFunctionsGL(context);
948 StateManagerGL *stateManager = GetStateManagerGL(context);
949 const angle::FeaturesGL &features = GetFeaturesGL(context);
950
951 nativegl::TexStorageFormat texStorageFormat =
952 nativegl::GetTexStorageFormat(functions, features, internalFormat);
953
954 stateManager->bindTexture(getType(), mTextureID);
955 if (nativegl::UseTexImage2D(getType()))
956 {
957 ASSERT(size.depth == 1);
958 if (functions->texStorage2D)
959 {
960 ANGLE_GL_TRY_ALWAYS_CHECK(
961 context,
962 functions->texStorage2D(ToGLenum(type), static_cast<GLsizei>(levels),
963 texStorageFormat.internalFormat, size.width, size.height));
964 }
965 else
966 {
967 // Make sure no pixel unpack buffer is bound
968 stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
969
970 const gl::InternalFormat &internalFormatInfo =
971 gl::GetSizedInternalFormatInfo(internalFormat);
972
973 // Internal format must be sized
974 ASSERT(internalFormatInfo.sized);
975
976 for (size_t level = 0; level < levels; level++)
977 {
978 gl::Extents levelSize(std::max(size.width >> level, 1),
979 std::max(size.height >> level, 1), 1);
980
981 if (getType() == gl::TextureType::_2D || getType() == gl::TextureType::Rectangle)
982 {
983 if (internalFormatInfo.compressed)
984 {
985 nativegl::CompressedTexSubImageFormat compressedTexImageFormat =
986 nativegl::GetCompressedSubTexImageFormat(functions, features,
987 internalFormat);
988
989 GLuint dataSize = 0;
990 ANGLE_CHECK_GL_MATH(
991 contextGL,
992 internalFormatInfo.computeCompressedImageSize(levelSize, &dataSize));
993 ANGLE_GL_TRY_ALWAYS_CHECK(
994 context,
995 functions->compressedTexImage2D(
996 ToGLenum(type), static_cast<GLint>(level),
997 compressedTexImageFormat.format, levelSize.width, levelSize.height,
998 0, static_cast<GLsizei>(dataSize), nullptr));
999 }
1000 else
1001 {
1002 nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
1003 functions, features, internalFormat, internalFormatInfo.format,
1004 internalFormatInfo.type);
1005
1006 ANGLE_GL_TRY_ALWAYS_CHECK(
1007 context,
1008 functions->texImage2D(ToGLenum(type), static_cast<GLint>(level),
1009 texImageFormat.internalFormat, levelSize.width,
1010 levelSize.height, 0, texImageFormat.format,
1011 texImageFormat.type, nullptr));
1012 }
1013 }
1014 else
1015 {
1016 ASSERT(getType() == gl::TextureType::CubeMap);
1017 for (gl::TextureTarget face : gl::AllCubeFaceTextureTargets())
1018 {
1019 if (internalFormatInfo.compressed)
1020 {
1021 nativegl::CompressedTexSubImageFormat compressedTexImageFormat =
1022 nativegl::GetCompressedSubTexImageFormat(functions, features,
1023 internalFormat);
1024
1025 GLuint dataSize = 0;
1026 ANGLE_CHECK_GL_MATH(contextGL,
1027 internalFormatInfo.computeCompressedImageSize(
1028 levelSize, &dataSize));
1029 ANGLE_GL_TRY_ALWAYS_CHECK(
1030 context,
1031 functions->compressedTexImage2D(
1032 ToGLenum(face), static_cast<GLint>(level),
1033 compressedTexImageFormat.format, levelSize.width,
1034 levelSize.height, 0, static_cast<GLsizei>(dataSize), nullptr));
1035 }
1036 else
1037 {
1038 nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
1039 functions, features, internalFormat, internalFormatInfo.format,
1040 internalFormatInfo.type);
1041
1042 ANGLE_GL_TRY_ALWAYS_CHECK(
1043 context, functions->texImage2D(
1044 ToGLenum(face), static_cast<GLint>(level),
1045 texImageFormat.internalFormat, levelSize.width,
1046 levelSize.height, 0, texImageFormat.format,
1047 texImageFormat.type, nullptr));
1048 }
1049 }
1050 }
1051 }
1052 }
1053 }
1054 else
1055 {
1056 ASSERT(nativegl::UseTexImage3D(getType()));
1057 if (functions->texStorage3D)
1058 {
1059 ANGLE_GL_TRY_ALWAYS_CHECK(
1060 context, functions->texStorage3D(ToGLenum(type), static_cast<GLsizei>(levels),
1061 texStorageFormat.internalFormat, size.width,
1062 size.height, size.depth));
1063 }
1064 else
1065 {
1066 // Make sure no pixel unpack buffer is bound
1067 stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
1068
1069 const gl::InternalFormat &internalFormatInfo =
1070 gl::GetSizedInternalFormatInfo(internalFormat);
1071
1072 // Internal format must be sized
1073 ASSERT(internalFormatInfo.sized);
1074
1075 for (GLsizei i = 0; i < static_cast<GLsizei>(levels); i++)
1076 {
1077 gl::Extents levelSize(
1078 std::max(size.width >> i, 1), std::max(size.height >> i, 1),
1079 getType() == gl::TextureType::_3D ? std::max(size.depth >> i, 1) : size.depth);
1080
1081 if (internalFormatInfo.compressed)
1082 {
1083 nativegl::CompressedTexSubImageFormat compressedTexImageFormat =
1084 nativegl::GetCompressedSubTexImageFormat(functions, features,
1085 internalFormat);
1086
1087 GLuint dataSize = 0;
1088 ANGLE_CHECK_GL_MATH(contextGL, internalFormatInfo.computeCompressedImageSize(
1089 levelSize, &dataSize));
1090 ANGLE_GL_TRY_ALWAYS_CHECK(
1091 context, functions->compressedTexImage3D(
1092 ToGLenum(type), i, compressedTexImageFormat.format,
1093 levelSize.width, levelSize.height, levelSize.depth, 0,
1094 static_cast<GLsizei>(dataSize), nullptr));
1095 }
1096 else
1097 {
1098 nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
1099 functions, features, internalFormat, internalFormatInfo.format,
1100 internalFormatInfo.type);
1101
1102 ANGLE_GL_TRY_ALWAYS_CHECK(
1103 context,
1104 functions->texImage3D(ToGLenum(type), i, texImageFormat.internalFormat,
1105 levelSize.width, levelSize.height, levelSize.depth, 0,
1106 texImageFormat.format, texImageFormat.type, nullptr));
1107 }
1108 }
1109 }
1110 }
1111
1112 setLevelInfo(context, type, 0, levels,
1113 GetLevelInfo(features, internalFormat, texStorageFormat.internalFormat));
1114
1115 return angle::Result::Continue;
1116 }
1117
setImageExternal(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type)1118 angle::Result TextureGL::setImageExternal(const gl::Context *context,
1119 const gl::ImageIndex &index,
1120 GLenum internalFormat,
1121 const gl::Extents &size,
1122 GLenum format,
1123 GLenum type)
1124 {
1125 const FunctionsGL *functions = GetFunctionsGL(context);
1126 const angle::FeaturesGL &features = GetFeaturesGL(context);
1127
1128 gl::TextureTarget target = index.getTarget();
1129 size_t level = static_cast<size_t>(index.getLevelIndex());
1130 nativegl::TexImageFormat texImageFormat =
1131 nativegl::GetTexImageFormat(functions, features, internalFormat, format, type);
1132
1133 setLevelInfo(context, target, level, 1,
1134 GetLevelInfo(features, internalFormat, texImageFormat.internalFormat));
1135 return angle::Result::Continue;
1136 }
1137
setStorageMultisample(const gl::Context * context,gl::TextureType type,GLsizei samples,GLint internalformat,const gl::Extents & size,bool fixedSampleLocations)1138 angle::Result TextureGL::setStorageMultisample(const gl::Context *context,
1139 gl::TextureType type,
1140 GLsizei samples,
1141 GLint internalformat,
1142 const gl::Extents &size,
1143 bool fixedSampleLocations)
1144 {
1145 const FunctionsGL *functions = GetFunctionsGL(context);
1146 StateManagerGL *stateManager = GetStateManagerGL(context);
1147 const angle::FeaturesGL &features = GetFeaturesGL(context);
1148
1149 nativegl::TexStorageFormat texStorageFormat =
1150 nativegl::GetTexStorageFormat(functions, features, internalformat);
1151
1152 stateManager->bindTexture(getType(), mTextureID);
1153
1154 if (nativegl::UseTexImage2D(getType()))
1155 {
1156 ASSERT(size.depth == 1);
1157 if (functions->texStorage2DMultisample)
1158 {
1159 ANGLE_GL_TRY_ALWAYS_CHECK(
1160 context, functions->texStorage2DMultisample(
1161 ToGLenum(type), samples, texStorageFormat.internalFormat, size.width,
1162 size.height, gl::ConvertToGLBoolean(fixedSampleLocations)));
1163 }
1164 else
1165 {
1166 // texImage2DMultisample is similar to texStorage2DMultisample of es 3.1 core feature,
1167 // On macos and some old drivers which doesn't support OpenGL ES 3.1, the function can
1168 // be supported by ARB_texture_multisample or OpenGL 3.2 core feature.
1169 ANGLE_GL_TRY_ALWAYS_CHECK(
1170 context, functions->texImage2DMultisample(
1171 ToGLenum(type), samples, texStorageFormat.internalFormat, size.width,
1172 size.height, gl::ConvertToGLBoolean(fixedSampleLocations)));
1173 }
1174 }
1175 else
1176 {
1177 ASSERT(nativegl::UseTexImage3D(getType()));
1178 ANGLE_GL_TRY_ALWAYS_CHECK(
1179 context, functions->texStorage3DMultisample(
1180 ToGLenum(type), samples, texStorageFormat.internalFormat, size.width,
1181 size.height, size.depth, gl::ConvertToGLBoolean(fixedSampleLocations)));
1182 }
1183
1184 setLevelInfo(context, type, 0, 1,
1185 GetLevelInfo(features, internalformat, texStorageFormat.internalFormat));
1186
1187 return angle::Result::Continue;
1188 }
1189
setStorageExternalMemory(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size,gl::MemoryObject * memoryObject,GLuint64 offset)1190 angle::Result TextureGL::setStorageExternalMemory(const gl::Context *context,
1191 gl::TextureType type,
1192 size_t levels,
1193 GLenum internalFormat,
1194 const gl::Extents &size,
1195 gl::MemoryObject *memoryObject,
1196 GLuint64 offset)
1197 {
1198 const FunctionsGL *functions = GetFunctionsGL(context);
1199 StateManagerGL *stateManager = GetStateManagerGL(context);
1200 const angle::FeaturesGL &features = GetFeaturesGL(context);
1201
1202 MemoryObjectGL *memoryObjectGL = GetImplAs<MemoryObjectGL>(memoryObject);
1203
1204 nativegl::TexStorageFormat texStorageFormat =
1205 nativegl::GetTexStorageFormat(functions, features, internalFormat);
1206
1207 stateManager->bindTexture(getType(), mTextureID);
1208 if (nativegl::UseTexImage2D(getType()))
1209 {
1210 ANGLE_GL_TRY_ALWAYS_CHECK(
1211 context,
1212 functions->texStorageMem2DEXT(ToGLenum(type), static_cast<GLsizei>(levels),
1213 texStorageFormat.internalFormat, size.width, size.height,
1214 memoryObjectGL->getMemoryObjectID(), offset));
1215 }
1216 else
1217 {
1218 ASSERT(nativegl::UseTexImage3D(getType()));
1219 ANGLE_GL_TRY_ALWAYS_CHECK(
1220 context,
1221 functions->texStorageMem3DEXT(ToGLenum(type), static_cast<GLsizei>(levels),
1222 texStorageFormat.internalFormat, size.width, size.height,
1223 size.depth, memoryObjectGL->getMemoryObjectID(), offset));
1224 }
1225
1226 setLevelInfo(context, type, 0, levels,
1227 GetLevelInfo(features, internalFormat, texStorageFormat.internalFormat));
1228
1229 return angle::Result::Continue;
1230 }
1231
setImageExternal(const gl::Context * context,gl::TextureType type,egl::Stream * stream,const egl::Stream::GLTextureDescription & desc)1232 angle::Result TextureGL::setImageExternal(const gl::Context *context,
1233 gl::TextureType type,
1234 egl::Stream *stream,
1235 const egl::Stream::GLTextureDescription &desc)
1236 {
1237 ANGLE_GL_UNREACHABLE(GetImplAs<ContextGL>(context));
1238 return angle::Result::Stop;
1239 }
1240
generateMipmap(const gl::Context * context)1241 angle::Result TextureGL::generateMipmap(const gl::Context *context)
1242 {
1243 const FunctionsGL *functions = GetFunctionsGL(context);
1244 StateManagerGL *stateManager = GetStateManagerGL(context);
1245
1246 stateManager->bindTexture(getType(), mTextureID);
1247 ANGLE_GL_TRY_ALWAYS_CHECK(context, functions->generateMipmap(ToGLenum(getType())));
1248
1249 const GLuint effectiveBaseLevel = mState.getEffectiveBaseLevel();
1250 const GLuint maxLevel = mState.getMipmapMaxLevel();
1251
1252 setLevelInfo(context, getType(), effectiveBaseLevel, maxLevel - effectiveBaseLevel,
1253 getBaseLevelInfo());
1254
1255 return angle::Result::Continue;
1256 }
1257
bindTexImage(const gl::Context * context,egl::Surface * surface)1258 angle::Result TextureGL::bindTexImage(const gl::Context *context, egl::Surface *surface)
1259 {
1260 ASSERT(getType() == gl::TextureType::_2D || getType() == gl::TextureType::Rectangle);
1261
1262 StateManagerGL *stateManager = GetStateManagerGL(context);
1263
1264 // Make sure this texture is bound
1265 stateManager->bindTexture(getType(), mTextureID);
1266
1267 SurfaceGL *surfaceGL = GetImplAs<SurfaceGL>(surface);
1268
1269 setLevelInfo(context, getType(), 0, 1,
1270 LevelInfoGL(GL_NONE, GL_NONE, false, LUMAWorkaroundGL(),
1271 surfaceGL->hasEmulatedAlphaChannel()));
1272 return angle::Result::Continue;
1273 }
1274
releaseTexImage(const gl::Context * context)1275 angle::Result TextureGL::releaseTexImage(const gl::Context *context)
1276 {
1277 ASSERT(getType() == gl::TextureType::_2D || getType() == gl::TextureType::Rectangle);
1278
1279 const angle::FeaturesGL &features = GetFeaturesGL(context);
1280 if (!features.resettingTexturesGeneratesErrors.enabled)
1281 {
1282 // Not all Surface implementations reset the size of mip 0 when releasing, do it manually
1283 const FunctionsGL *functions = GetFunctionsGL(context);
1284 StateManagerGL *stateManager = GetStateManagerGL(context);
1285
1286 stateManager->bindTexture(getType(), mTextureID);
1287 ASSERT(nativegl::UseTexImage2D(getType()));
1288 ANGLE_GL_TRY(context, functions->texImage2D(ToGLenum(getType()), 0, GL_RGBA, 0, 0, 0,
1289 GL_RGBA, GL_UNSIGNED_BYTE, nullptr));
1290 }
1291
1292 return angle::Result::Continue;
1293 }
1294
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)1295 angle::Result TextureGL::setEGLImageTarget(const gl::Context *context,
1296 gl::TextureType type,
1297 egl::Image *image)
1298 {
1299 const angle::FeaturesGL &features = GetFeaturesGL(context);
1300
1301 ImageGL *imageGL = GetImplAs<ImageGL>(image);
1302
1303 GLenum imageNativeInternalFormat = GL_NONE;
1304 ANGLE_TRY(imageGL->setTexture2D(context, type, this, &imageNativeInternalFormat));
1305
1306 setLevelInfo(
1307 context, type, 0, 1,
1308 GetLevelInfo(features, image->getFormat().info->internalFormat, imageNativeInternalFormat));
1309
1310 return angle::Result::Continue;
1311 }
1312
getNativeID() const1313 GLint TextureGL::getNativeID() const
1314 {
1315 return mTextureID;
1316 }
1317
syncState(const gl::Context * context,const gl::Texture::DirtyBits & dirtyBits)1318 angle::Result TextureGL::syncState(const gl::Context *context,
1319 const gl::Texture::DirtyBits &dirtyBits)
1320 {
1321 if (dirtyBits.none() && mLocalDirtyBits.none())
1322 {
1323 return angle::Result::Continue;
1324 }
1325
1326 const FunctionsGL *functions = GetFunctionsGL(context);
1327 StateManagerGL *stateManager = GetStateManagerGL(context);
1328
1329 stateManager->bindTexture(getType(), mTextureID);
1330
1331 if (dirtyBits[gl::Texture::DIRTY_BIT_BASE_LEVEL] || dirtyBits[gl::Texture::DIRTY_BIT_MAX_LEVEL])
1332 {
1333 // Don't know if the previous base level was using any workarounds, always re-sync the
1334 // workaround dirty bits
1335 mLocalDirtyBits |= GetLevelWorkaroundDirtyBits();
1336 }
1337 for (auto dirtyBit : (dirtyBits | mLocalDirtyBits))
1338 {
1339
1340 switch (dirtyBit)
1341 {
1342 case gl::Texture::DIRTY_BIT_MIN_FILTER:
1343 mAppliedSampler.setMinFilter(mState.getSamplerState().getMinFilter());
1344 ANGLE_GL_TRY(context, functions->texParameteri(
1345 nativegl::GetTextureBindingTarget(getType()),
1346 GL_TEXTURE_MIN_FILTER, mAppliedSampler.getMinFilter()));
1347 break;
1348 case gl::Texture::DIRTY_BIT_MAG_FILTER:
1349 mAppliedSampler.setMagFilter(mState.getSamplerState().getMagFilter());
1350 ANGLE_GL_TRY(context, functions->texParameteri(
1351 nativegl::GetTextureBindingTarget(getType()),
1352 GL_TEXTURE_MAG_FILTER, mAppliedSampler.getMagFilter()));
1353 break;
1354 case gl::Texture::DIRTY_BIT_WRAP_S:
1355 mAppliedSampler.setWrapS(mState.getSamplerState().getWrapS());
1356 ANGLE_GL_TRY(context, functions->texParameteri(
1357 nativegl::GetTextureBindingTarget(getType()),
1358 GL_TEXTURE_WRAP_S, mAppliedSampler.getWrapS()));
1359 break;
1360 case gl::Texture::DIRTY_BIT_WRAP_T:
1361 mAppliedSampler.setWrapT(mState.getSamplerState().getWrapT());
1362 ANGLE_GL_TRY(context, functions->texParameteri(
1363 nativegl::GetTextureBindingTarget(getType()),
1364 GL_TEXTURE_WRAP_T, mAppliedSampler.getWrapT()));
1365 break;
1366 case gl::Texture::DIRTY_BIT_WRAP_R:
1367 mAppliedSampler.setWrapR(mState.getSamplerState().getWrapR());
1368 ANGLE_GL_TRY(context, functions->texParameteri(
1369 nativegl::GetTextureBindingTarget(getType()),
1370 GL_TEXTURE_WRAP_R, mAppliedSampler.getWrapR()));
1371 break;
1372 case gl::Texture::DIRTY_BIT_MAX_ANISOTROPY:
1373 mAppliedSampler.setMaxAnisotropy(mState.getSamplerState().getMaxAnisotropy());
1374 ANGLE_GL_TRY(context,
1375 functions->texParameterf(nativegl::GetTextureBindingTarget(getType()),
1376 GL_TEXTURE_MAX_ANISOTROPY_EXT,
1377 mAppliedSampler.getMaxAnisotropy()));
1378 break;
1379 case gl::Texture::DIRTY_BIT_MIN_LOD:
1380 mAppliedSampler.setMinLod(mState.getSamplerState().getMinLod());
1381 ANGLE_GL_TRY(context, functions->texParameterf(
1382 nativegl::GetTextureBindingTarget(getType()),
1383 GL_TEXTURE_MIN_LOD, mAppliedSampler.getMinLod()));
1384 break;
1385 case gl::Texture::DIRTY_BIT_MAX_LOD:
1386 mAppliedSampler.setMaxLod(mState.getSamplerState().getMaxLod());
1387 ANGLE_GL_TRY(context, functions->texParameterf(
1388 nativegl::GetTextureBindingTarget(getType()),
1389 GL_TEXTURE_MAX_LOD, mAppliedSampler.getMaxLod()));
1390 break;
1391 case gl::Texture::DIRTY_BIT_COMPARE_MODE:
1392 mAppliedSampler.setCompareMode(mState.getSamplerState().getCompareMode());
1393 ANGLE_GL_TRY(context,
1394 functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1395 GL_TEXTURE_COMPARE_MODE,
1396 mAppliedSampler.getCompareMode()));
1397 break;
1398 case gl::Texture::DIRTY_BIT_COMPARE_FUNC:
1399 mAppliedSampler.setCompareFunc(mState.getSamplerState().getCompareFunc());
1400 ANGLE_GL_TRY(context,
1401 functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1402 GL_TEXTURE_COMPARE_FUNC,
1403 mAppliedSampler.getCompareFunc()));
1404 break;
1405 case gl::Texture::DIRTY_BIT_SRGB_DECODE:
1406 mAppliedSampler.setSRGBDecode(mState.getSamplerState().getSRGBDecode());
1407 ANGLE_GL_TRY(context,
1408 functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1409 GL_TEXTURE_SRGB_DECODE_EXT,
1410 mAppliedSampler.getSRGBDecode()));
1411 break;
1412 case gl::Texture::DIRTY_BIT_BORDER_COLOR:
1413 {
1414 const angle::ColorGeneric &borderColor(mState.getSamplerState().getBorderColor());
1415 mAppliedSampler.setBorderColor(borderColor);
1416 switch (borderColor.type)
1417 {
1418 case angle::ColorGeneric::Type::Float:
1419 ANGLE_GL_TRY(context,
1420 functions->texParameterfv(
1421 nativegl::GetTextureBindingTarget(getType()),
1422 GL_TEXTURE_BORDER_COLOR, &borderColor.colorF.red));
1423 break;
1424 case angle::ColorGeneric::Type::Int:
1425 ANGLE_GL_TRY(context,
1426 functions->texParameterIiv(
1427 nativegl::GetTextureBindingTarget(getType()),
1428 GL_TEXTURE_BORDER_COLOR, &borderColor.colorI.red));
1429 break;
1430 case angle::ColorGeneric::Type::UInt:
1431 ANGLE_GL_TRY(context,
1432 functions->texParameterIuiv(
1433 nativegl::GetTextureBindingTarget(getType()),
1434 GL_TEXTURE_BORDER_COLOR, &borderColor.colorUI.red));
1435 break;
1436 default:
1437 UNREACHABLE();
1438 break;
1439 }
1440 break;
1441 }
1442
1443 // Texture state
1444 case gl::Texture::DIRTY_BIT_SWIZZLE_RED:
1445 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_R,
1446 mState.getSwizzleState().swizzleRed,
1447 &mAppliedSwizzle.swizzleRed));
1448 break;
1449 case gl::Texture::DIRTY_BIT_SWIZZLE_GREEN:
1450 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_G,
1451 mState.getSwizzleState().swizzleGreen,
1452 &mAppliedSwizzle.swizzleGreen));
1453 break;
1454 case gl::Texture::DIRTY_BIT_SWIZZLE_BLUE:
1455 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_B,
1456 mState.getSwizzleState().swizzleBlue,
1457 &mAppliedSwizzle.swizzleBlue));
1458 break;
1459 case gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA:
1460 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_A,
1461 mState.getSwizzleState().swizzleAlpha,
1462 &mAppliedSwizzle.swizzleAlpha));
1463 break;
1464 case gl::Texture::DIRTY_BIT_BASE_LEVEL:
1465 mAppliedBaseLevel = mState.getEffectiveBaseLevel();
1466 ANGLE_GL_TRY(context,
1467 functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1468 GL_TEXTURE_BASE_LEVEL, mAppliedBaseLevel));
1469 break;
1470 case gl::Texture::DIRTY_BIT_MAX_LEVEL:
1471 mAppliedMaxLevel = mState.getEffectiveMaxLevel();
1472 ANGLE_GL_TRY(context,
1473 functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1474 GL_TEXTURE_MAX_LEVEL, mAppliedMaxLevel));
1475 break;
1476 case gl::Texture::DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE:
1477 {
1478 GLenum mDepthStencilTextureMode = mState.getDepthStencilTextureMode();
1479 ANGLE_GL_TRY(context, functions->texParameteri(
1480 nativegl::GetTextureBindingTarget(getType()),
1481 GL_DEPTH_STENCIL_TEXTURE_MODE, mDepthStencilTextureMode));
1482 break;
1483 }
1484 case gl::Texture::DIRTY_BIT_USAGE:
1485 break;
1486 case gl::Texture::DIRTY_BIT_LABEL:
1487 break;
1488
1489 case gl::Texture::DIRTY_BIT_IMPLEMENTATION:
1490 // This special dirty bit is used to signal the front-end that the implementation
1491 // has local dirty bits. The real dirty bits are in mLocalDirty bits.
1492 break;
1493 case gl::Texture::DIRTY_BIT_BOUND_AS_IMAGE:
1494 // Only used for Vulkan.
1495 break;
1496
1497 default:
1498 UNREACHABLE();
1499 }
1500 }
1501
1502 mLocalDirtyBits.reset();
1503 return angle::Result::Continue;
1504 }
1505
hasAnyDirtyBit() const1506 bool TextureGL::hasAnyDirtyBit() const
1507 {
1508 return mLocalDirtyBits.any();
1509 }
1510
setBaseLevel(const gl::Context * context,GLuint baseLevel)1511 angle::Result TextureGL::setBaseLevel(const gl::Context *context, GLuint baseLevel)
1512 {
1513 if (baseLevel != mAppliedBaseLevel)
1514 {
1515 const FunctionsGL *functions = GetFunctionsGL(context);
1516 StateManagerGL *stateManager = GetStateManagerGL(context);
1517
1518 mAppliedBaseLevel = baseLevel;
1519 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_BASE_LEVEL);
1520
1521 // Signal to the GL layer that the Impl has dirty bits.
1522 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1523
1524 stateManager->bindTexture(getType(), mTextureID);
1525 ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_BASE_LEVEL,
1526 baseLevel));
1527 }
1528 return angle::Result::Continue;
1529 }
1530
setMaxLevel(const gl::Context * context,GLuint maxLevel)1531 angle::Result TextureGL::setMaxLevel(const gl::Context *context, GLuint maxLevel)
1532 {
1533 if (maxLevel != mAppliedMaxLevel)
1534 {
1535 const FunctionsGL *functions = GetFunctionsGL(context);
1536 StateManagerGL *stateManager = GetStateManagerGL(context);
1537
1538 mAppliedMaxLevel = maxLevel;
1539 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MAX_LEVEL);
1540
1541 // Signal to the GL layer that the Impl has dirty bits.
1542 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1543
1544 stateManager->bindTexture(getType(), mTextureID);
1545 ANGLE_GL_TRY(context,
1546 functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MAX_LEVEL, maxLevel));
1547 }
1548 return angle::Result::Continue;
1549 }
1550
setMinFilter(const gl::Context * context,GLenum filter)1551 angle::Result TextureGL::setMinFilter(const gl::Context *context, GLenum filter)
1552 {
1553 if (filter != mAppliedSampler.getMinFilter())
1554 {
1555 const FunctionsGL *functions = GetFunctionsGL(context);
1556 StateManagerGL *stateManager = GetStateManagerGL(context);
1557
1558 mAppliedSampler.setMinFilter(filter);
1559 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MIN_FILTER);
1560
1561 // Signal to the GL layer that the Impl has dirty bits.
1562 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1563
1564 stateManager->bindTexture(getType(), mTextureID);
1565 ANGLE_GL_TRY(context,
1566 functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MIN_FILTER, filter));
1567 }
1568 return angle::Result::Continue;
1569 }
setMagFilter(const gl::Context * context,GLenum filter)1570 angle::Result TextureGL::setMagFilter(const gl::Context *context, GLenum filter)
1571 {
1572 if (filter != mAppliedSampler.getMagFilter())
1573 {
1574 const FunctionsGL *functions = GetFunctionsGL(context);
1575 StateManagerGL *stateManager = GetStateManagerGL(context);
1576
1577 mAppliedSampler.setMagFilter(filter);
1578 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MAG_FILTER);
1579
1580 // Signal to the GL layer that the Impl has dirty bits.
1581 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1582
1583 stateManager->bindTexture(getType(), mTextureID);
1584 ANGLE_GL_TRY(context,
1585 functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MAG_FILTER, filter));
1586 }
1587 return angle::Result::Continue;
1588 }
1589
setSwizzle(const gl::Context * context,GLint swizzle[4])1590 angle::Result TextureGL::setSwizzle(const gl::Context *context, GLint swizzle[4])
1591 {
1592 gl::SwizzleState resultingSwizzle =
1593 gl::SwizzleState(swizzle[0], swizzle[1], swizzle[2], swizzle[3]);
1594
1595 if (resultingSwizzle != mAppliedSwizzle)
1596 {
1597 const FunctionsGL *functions = GetFunctionsGL(context);
1598 StateManagerGL *stateManager = GetStateManagerGL(context);
1599
1600 mAppliedSwizzle = resultingSwizzle;
1601 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_RED);
1602 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_GREEN);
1603 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_BLUE);
1604 mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA);
1605
1606 // Signal to the GL layer that the Impl has dirty bits.
1607 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1608
1609 stateManager->bindTexture(getType(), mTextureID);
1610 ANGLE_GL_TRY(context, functions->texParameteriv(ToGLenum(getType()),
1611 GL_TEXTURE_SWIZZLE_RGBA, swizzle));
1612 }
1613 return angle::Result::Continue;
1614 }
1615
getNativeInternalFormat(const gl::ImageIndex & index) const1616 GLenum TextureGL::getNativeInternalFormat(const gl::ImageIndex &index) const
1617 {
1618 return getLevelInfo(index.getTarget(), index.getLevelIndex()).nativeInternalFormat;
1619 }
1620
hasEmulatedAlphaChannel(const gl::ImageIndex & index) const1621 bool TextureGL::hasEmulatedAlphaChannel(const gl::ImageIndex &index) const
1622 {
1623 return getLevelInfo(index.getTargetOrFirstCubeFace(), index.getLevelIndex())
1624 .emulatedAlphaChannel;
1625 }
1626
syncTextureStateSwizzle(const gl::Context * context,const FunctionsGL * functions,GLenum name,GLenum value,GLenum * outValue)1627 angle::Result TextureGL::syncTextureStateSwizzle(const gl::Context *context,
1628 const FunctionsGL *functions,
1629 GLenum name,
1630 GLenum value,
1631 GLenum *outValue)
1632 {
1633 const LevelInfoGL &levelInfo = getBaseLevelInfo();
1634 GLenum resultSwizzle = value;
1635 if (levelInfo.lumaWorkaround.enabled)
1636 {
1637 switch (value)
1638 {
1639 case GL_RED:
1640 case GL_GREEN:
1641 case GL_BLUE:
1642 if (levelInfo.sourceFormat == GL_LUMINANCE ||
1643 levelInfo.sourceFormat == GL_LUMINANCE_ALPHA)
1644 {
1645 // Texture is backed by a RED or RG texture, point all color channels at the
1646 // red channel.
1647 ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RED ||
1648 levelInfo.lumaWorkaround.workaroundFormat == GL_RG);
1649 resultSwizzle = GL_RED;
1650 }
1651 else
1652 {
1653 ASSERT(levelInfo.sourceFormat == GL_ALPHA);
1654 // Color channels are not supposed to exist, make them always sample 0.
1655 resultSwizzle = GL_ZERO;
1656 }
1657 break;
1658
1659 case GL_ALPHA:
1660 if (levelInfo.sourceFormat == GL_LUMINANCE)
1661 {
1662 // Alpha channel is not supposed to exist, make it always sample 1.
1663 resultSwizzle = GL_ONE;
1664 }
1665 else if (levelInfo.sourceFormat == GL_ALPHA)
1666 {
1667 // Texture is backed by a RED texture, point the alpha channel at the red
1668 // channel.
1669 ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RED);
1670 resultSwizzle = GL_RED;
1671 }
1672 else
1673 {
1674 ASSERT(levelInfo.sourceFormat == GL_LUMINANCE_ALPHA);
1675 // Texture is backed by an RG texture, point the alpha channel at the green
1676 // channel.
1677 ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RG);
1678 resultSwizzle = GL_GREEN;
1679 }
1680 break;
1681
1682 case GL_ZERO:
1683 case GL_ONE:
1684 // Don't modify the swizzle state when requesting ZERO or ONE.
1685 resultSwizzle = value;
1686 break;
1687
1688 default:
1689 UNREACHABLE();
1690 break;
1691 }
1692 }
1693 else if (levelInfo.depthStencilWorkaround)
1694 {
1695 switch (value)
1696 {
1697 case GL_RED:
1698 // Don't modify the swizzle state when requesting the red channel.
1699 resultSwizzle = value;
1700 break;
1701
1702 case GL_GREEN:
1703 case GL_BLUE:
1704 if (context->getClientMajorVersion() <= 2)
1705 {
1706 // In OES_depth_texture/ARB_depth_texture, depth
1707 // textures are treated as luminance.
1708 resultSwizzle = GL_RED;
1709 }
1710 else
1711 {
1712 // In GLES 3.0, depth textures are treated as RED
1713 // textures, so green and blue should be 0.
1714 resultSwizzle = GL_ZERO;
1715 }
1716 break;
1717
1718 case GL_ALPHA:
1719 // Depth textures should sample 1 from the alpha channel.
1720 resultSwizzle = GL_ONE;
1721 break;
1722
1723 case GL_ZERO:
1724 case GL_ONE:
1725 // Don't modify the swizzle state when requesting ZERO or ONE.
1726 resultSwizzle = value;
1727 break;
1728
1729 default:
1730 UNREACHABLE();
1731 break;
1732 }
1733 }
1734 else if (levelInfo.emulatedAlphaChannel)
1735 {
1736 if (value == GL_ALPHA)
1737 {
1738 resultSwizzle = GL_ONE;
1739 }
1740 }
1741
1742 *outValue = resultSwizzle;
1743 ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()), name, resultSwizzle));
1744
1745 return angle::Result::Continue;
1746 }
1747
setLevelInfo(const gl::Context * context,gl::TextureTarget target,size_t level,size_t levelCount,const LevelInfoGL & levelInfo)1748 void TextureGL::setLevelInfo(const gl::Context *context,
1749 gl::TextureTarget target,
1750 size_t level,
1751 size_t levelCount,
1752 const LevelInfoGL &levelInfo)
1753 {
1754 ASSERT(levelCount > 0);
1755
1756 bool updateWorkarounds = levelInfo.depthStencilWorkaround || levelInfo.lumaWorkaround.enabled ||
1757 levelInfo.emulatedAlphaChannel;
1758
1759 for (size_t i = level; i < level + levelCount; i++)
1760 {
1761 size_t index = GetLevelInfoIndex(target, i);
1762 ASSERT(index < mLevelInfo.size());
1763 auto &curLevelInfo = mLevelInfo[index];
1764
1765 updateWorkarounds |= curLevelInfo.depthStencilWorkaround;
1766 updateWorkarounds |= curLevelInfo.lumaWorkaround.enabled;
1767 updateWorkarounds |= curLevelInfo.emulatedAlphaChannel;
1768
1769 curLevelInfo = levelInfo;
1770 }
1771
1772 if (updateWorkarounds)
1773 {
1774 mLocalDirtyBits |= GetLevelWorkaroundDirtyBits();
1775 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1776 }
1777 }
1778
setLevelInfo(const gl::Context * context,gl::TextureType type,size_t level,size_t levelCount,const LevelInfoGL & levelInfo)1779 void TextureGL::setLevelInfo(const gl::Context *context,
1780 gl::TextureType type,
1781 size_t level,
1782 size_t levelCount,
1783 const LevelInfoGL &levelInfo)
1784 {
1785 if (type == gl::TextureType::CubeMap)
1786 {
1787 for (gl::TextureTarget target : gl::AllCubeFaceTextureTargets())
1788 {
1789 setLevelInfo(context, target, level, levelCount, levelInfo);
1790 }
1791 }
1792 else
1793 {
1794 setLevelInfo(context, NonCubeTextureTypeToTarget(type), level, levelCount, levelInfo);
1795 }
1796 }
1797
getLevelInfo(gl::TextureTarget target,size_t level) const1798 const LevelInfoGL &TextureGL::getLevelInfo(gl::TextureTarget target, size_t level) const
1799 {
1800 return mLevelInfo[GetLevelInfoIndex(target, level)];
1801 }
1802
getBaseLevelInfo() const1803 const LevelInfoGL &TextureGL::getBaseLevelInfo() const
1804 {
1805 GLint effectiveBaseLevel = mState.getEffectiveBaseLevel();
1806 gl::TextureTarget target = getType() == gl::TextureType::CubeMap
1807 ? gl::kCubeMapTextureTargetMin
1808 : gl::NonCubeTextureTypeToTarget(getType());
1809 return getLevelInfo(target, effectiveBaseLevel);
1810 }
1811
getType() const1812 gl::TextureType TextureGL::getType() const
1813 {
1814 return mState.mType;
1815 }
1816
initializeContents(const gl::Context * context,const gl::ImageIndex & imageIndex)1817 angle::Result TextureGL::initializeContents(const gl::Context *context,
1818 const gl::ImageIndex &imageIndex)
1819 {
1820 ContextGL *contextGL = GetImplAs<ContextGL>(context);
1821 const FunctionsGL *functions = GetFunctionsGL(context);
1822 StateManagerGL *stateManager = GetStateManagerGL(context);
1823 const angle::FeaturesGL &features = GetFeaturesGL(context);
1824
1825 bool shouldUseClear = !nativegl::SupportsTexImage(getType());
1826 GLenum nativeInternalFormat =
1827 getLevelInfo(imageIndex.getTarget(), imageIndex.getLevelIndex()).nativeInternalFormat;
1828 if ((features.allowClearForRobustResourceInit.enabled || shouldUseClear) &&
1829 nativegl::SupportsNativeRendering(functions, mState.getType(), nativeInternalFormat))
1830 {
1831 BlitGL *blitter = GetBlitGL(context);
1832
1833 int levelDepth = mState.getImageDesc(imageIndex).size.depth;
1834
1835 bool clearSucceeded = false;
1836 ANGLE_TRY(blitter->clearRenderableTexture(context, this, nativeInternalFormat, levelDepth,
1837 imageIndex, &clearSucceeded));
1838 if (clearSucceeded)
1839 {
1840 return angle::Result::Continue;
1841 }
1842 }
1843
1844 // Either the texture is not renderable or was incomplete when clearing, fall back to a data
1845 // upload
1846 ASSERT(nativegl::SupportsTexImage(getType()));
1847 const gl::ImageDesc &desc = mState.getImageDesc(imageIndex);
1848 const gl::InternalFormat &internalFormatInfo = *desc.format.info;
1849
1850 gl::PixelUnpackState unpackState;
1851 unpackState.alignment = 1;
1852 stateManager->setPixelUnpackState(unpackState);
1853
1854 GLuint prevUnpackBuffer = stateManager->getBufferID(gl::BufferBinding::PixelUnpack);
1855 stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
1856
1857 stateManager->bindTexture(getType(), mTextureID);
1858 if (internalFormatInfo.compressed)
1859 {
1860 nativegl::CompressedTexSubImageFormat nativeSubImageFormat =
1861 nativegl::GetCompressedSubTexImageFormat(functions, features,
1862 internalFormatInfo.internalFormat);
1863
1864 GLuint imageSize = 0;
1865 ANGLE_CHECK_GL_MATH(contextGL,
1866 internalFormatInfo.computeCompressedImageSize(desc.size, &imageSize));
1867
1868 angle::MemoryBuffer *zero;
1869 ANGLE_CHECK_GL_ALLOC(contextGL, context->getZeroFilledBuffer(imageSize, &zero));
1870
1871 // WebGL spec requires that zero data is uploaded to compressed textures even if it might
1872 // not result in zero color data.
1873 if (nativegl::UseTexImage2D(getType()))
1874 {
1875 ANGLE_GL_TRY(context, functions->compressedTexSubImage2D(
1876 ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(),
1877 0, 0, desc.size.width, desc.size.height,
1878 nativeSubImageFormat.format, imageSize, zero->data()));
1879 }
1880 else
1881 {
1882 ASSERT(nativegl::UseTexImage3D(getType()));
1883 ANGLE_GL_TRY(context, functions->compressedTexSubImage3D(
1884 ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(),
1885 0, 0, 0, desc.size.width, desc.size.height, desc.size.depth,
1886 nativeSubImageFormat.format, imageSize, zero->data()));
1887 }
1888 }
1889 else
1890 {
1891 nativegl::TexSubImageFormat nativeSubImageFormat = nativegl::GetTexSubImageFormat(
1892 functions, features, internalFormatInfo.format, internalFormatInfo.type);
1893
1894 GLuint imageSize = 0;
1895 ANGLE_CHECK_GL_MATH(contextGL, internalFormatInfo.computePackUnpackEndByte(
1896 nativeSubImageFormat.type, desc.size, unpackState,
1897 nativegl::UseTexImage3D(getType()), &imageSize));
1898
1899 angle::MemoryBuffer *zero;
1900 ANGLE_CHECK_GL_ALLOC(contextGL, context->getZeroFilledBuffer(imageSize, &zero));
1901
1902 if (nativegl::UseTexImage2D(getType()))
1903 {
1904 ANGLE_GL_TRY(context,
1905 functions->texSubImage2D(ToGLenum(imageIndex.getTarget()),
1906 imageIndex.getLevelIndex(), 0, 0, desc.size.width,
1907 desc.size.height, nativeSubImageFormat.format,
1908 nativeSubImageFormat.type, zero->data()));
1909 }
1910 else
1911 {
1912 ASSERT(nativegl::UseTexImage3D(getType()));
1913 ANGLE_GL_TRY(context,
1914 functions->texSubImage3D(
1915 ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(), 0, 0, 0,
1916 desc.size.width, desc.size.height, desc.size.depth,
1917 nativeSubImageFormat.format, nativeSubImageFormat.type, zero->data()));
1918 }
1919 }
1920
1921 // Reset the pixel unpack state. Because this call is made after synchronizing dirty bits in a
1922 // glTexImage call, we need to make sure that the texture data to be uploaded later has the
1923 // expected unpack state.
1924 stateManager->setPixelUnpackState(context->getState().getUnpackState());
1925 stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, prevUnpackBuffer);
1926
1927 return angle::Result::Continue;
1928 }
1929
1930 } // namespace rx
1931