• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // Texture.cpp: Implements the Texture class and its derived classes
16 // Texture2D, TextureCubeMap, Texture3D and Texture2DArray. Implements GL texture objects
17 // and related functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
18 
19 #include "Texture.h"
20 
21 #include "main.h"
22 #include "mathutil.h"
23 #include "Framebuffer.h"
24 #include "Device.hpp"
25 #include "Sampler.h"
26 #include "Shader.h"
27 #include "libEGL/Display.h"
28 #include "common/Surface.hpp"
29 #include "common/debug.h"
30 
31 #include <algorithm>
32 
33 namespace es2
34 {
35 
getNullImage()36 egl::Image*& ImageLevels::getNullImage()
37 {
38     static egl::Image* nullImage;
39     nullImage = nullptr;
40     return nullImage;
41 }
42 
Texture(GLuint name)43 Texture::Texture(GLuint name) : egl::Texture(name)
44 {
45 	mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
46 	mMagFilter = GL_LINEAR;
47 	mWrapS = GL_REPEAT;
48 	mWrapT = GL_REPEAT;
49 	mWrapR = GL_REPEAT;
50 	mMaxAnisotropy = 1.0f;
51 	mBaseLevel = 0;
52 	mCompareFunc = GL_LEQUAL;
53 	mCompareMode = GL_NONE;
54 	mImmutableFormat = GL_FALSE;
55 	mImmutableLevels = 0;
56 	mMaxLevel = 1000;
57 	mMaxLOD = 1000;
58 	mMinLOD = -1000;
59 	mSwizzleR = GL_RED;
60 	mSwizzleG = GL_GREEN;
61 	mSwizzleB = GL_BLUE;
62 	mSwizzleA = GL_ALPHA;
63 
64 	resource = new sw::Resource(0);
65 }
66 
~Texture()67 Texture::~Texture()
68 {
69 	resource->destruct();
70 }
71 
getResource() const72 sw::Resource *Texture::getResource() const
73 {
74 	return resource;
75 }
76 
77 // Returns true on successful filter state update (valid enum parameter)
setMinFilter(GLenum filter)78 bool Texture::setMinFilter(GLenum filter)
79 {
80 	switch(filter)
81 	{
82 	case GL_NEAREST_MIPMAP_NEAREST:
83 	case GL_LINEAR_MIPMAP_NEAREST:
84 	case GL_NEAREST_MIPMAP_LINEAR:
85 	case GL_LINEAR_MIPMAP_LINEAR:
86 		if((getTarget() == GL_TEXTURE_EXTERNAL_OES) || (getTarget() == GL_TEXTURE_RECTANGLE_ARB))
87 		{
88 			return false;
89 		}
90 		// Fall through
91 	case GL_NEAREST:
92 	case GL_LINEAR:
93 		mMinFilter = filter;
94 		return true;
95 	default:
96 		return false;
97 	}
98 }
99 
100 // Returns true on successful filter state update (valid enum parameter)
setMagFilter(GLenum filter)101 bool Texture::setMagFilter(GLenum filter)
102 {
103 	switch(filter)
104 	{
105 	case GL_NEAREST:
106 	case GL_LINEAR:
107 		mMagFilter = filter;
108 		return true;
109 	default:
110 		return false;
111 	}
112 }
113 
114 // Returns true on successful wrap state update (valid enum parameter)
setWrapS(GLenum wrap)115 bool Texture::setWrapS(GLenum wrap)
116 {
117 	switch(wrap)
118 	{
119 	case GL_REPEAT:
120 	case GL_MIRRORED_REPEAT:
121 		if((getTarget() == GL_TEXTURE_EXTERNAL_OES) || (getTarget() == GL_TEXTURE_RECTANGLE_ARB))
122 		{
123 			return false;
124 		}
125 		// Fall through
126 	case GL_CLAMP_TO_EDGE:
127 		mWrapS = wrap;
128 		return true;
129 	default:
130 		return false;
131 	}
132 }
133 
134 // Returns true on successful wrap state update (valid enum parameter)
setWrapT(GLenum wrap)135 bool Texture::setWrapT(GLenum wrap)
136 {
137 	switch(wrap)
138 	{
139 	case GL_REPEAT:
140 	case GL_MIRRORED_REPEAT:
141 		if((getTarget() == GL_TEXTURE_EXTERNAL_OES) || (getTarget() == GL_TEXTURE_RECTANGLE_ARB))
142 		{
143 			return false;
144 		}
145 		// Fall through
146 	case GL_CLAMP_TO_EDGE:
147 		mWrapT = wrap;
148 		return true;
149 	default:
150 		return false;
151 	}
152 }
153 
154 // Returns true on successful wrap state update (valid enum parameter)
setWrapR(GLenum wrap)155 bool Texture::setWrapR(GLenum wrap)
156 {
157 	switch(wrap)
158 	{
159 	case GL_REPEAT:
160 	case GL_MIRRORED_REPEAT:
161 		if((getTarget() == GL_TEXTURE_EXTERNAL_OES) || (getTarget() == GL_TEXTURE_RECTANGLE_ARB))
162 		{
163 			return false;
164 		}
165 		// Fall through
166 	case GL_CLAMP_TO_EDGE:
167 		mWrapR = wrap;
168 		return true;
169 	default:
170 		return false;
171 	}
172 }
173 
174 // Returns true on successful max anisotropy update (valid anisotropy value)
setMaxAnisotropy(float textureMaxAnisotropy)175 bool Texture::setMaxAnisotropy(float textureMaxAnisotropy)
176 {
177 	textureMaxAnisotropy = std::min(textureMaxAnisotropy, MAX_TEXTURE_MAX_ANISOTROPY);
178 
179 	if(textureMaxAnisotropy < 1.0f)
180 	{
181 		return false;
182 	}
183 
184 	if(mMaxAnisotropy != textureMaxAnisotropy)
185 	{
186 		mMaxAnisotropy = textureMaxAnisotropy;
187 	}
188 
189 	return true;
190 }
191 
setBaseLevel(GLint baseLevel)192 bool Texture::setBaseLevel(GLint baseLevel)
193 {
194 	if(baseLevel < 0)
195 	{
196 		return false;
197 	}
198 
199 	mBaseLevel = baseLevel;
200 	return true;
201 }
202 
setCompareFunc(GLenum compareFunc)203 bool Texture::setCompareFunc(GLenum compareFunc)
204 {
205 	switch(compareFunc)
206 	{
207 	case GL_LEQUAL:
208 	case GL_GEQUAL:
209 	case GL_LESS:
210 	case GL_GREATER:
211 	case GL_EQUAL:
212 	case GL_NOTEQUAL:
213 	case GL_ALWAYS:
214 	case GL_NEVER:
215 		mCompareFunc = compareFunc;
216 		return true;
217 	default:
218 		return false;
219 	}
220 }
221 
setCompareMode(GLenum compareMode)222 bool Texture::setCompareMode(GLenum compareMode)
223 {
224 	switch(compareMode)
225 	{
226 	case GL_COMPARE_REF_TO_TEXTURE:
227 	case GL_NONE:
228 		mCompareMode = compareMode;
229 		return true;
230 	default:
231 		return false;
232 	}
233 }
234 
makeImmutable(GLsizei levels)235 void Texture::makeImmutable(GLsizei levels)
236 {
237 	mImmutableFormat = GL_TRUE;
238 	mImmutableLevels = levels;
239 }
240 
setMaxLevel(GLint maxLevel)241 bool Texture::setMaxLevel(GLint maxLevel)
242 {
243 	mMaxLevel = maxLevel;
244 	return true;
245 }
246 
setMaxLOD(GLfloat maxLOD)247 bool Texture::setMaxLOD(GLfloat maxLOD)
248 {
249 	mMaxLOD = maxLOD;
250 	return true;
251 }
252 
setMinLOD(GLfloat minLOD)253 bool Texture::setMinLOD(GLfloat minLOD)
254 {
255 	mMinLOD = minLOD;
256 	return true;
257 }
258 
setSwizzleR(GLenum swizzleR)259 bool Texture::setSwizzleR(GLenum swizzleR)
260 {
261 	switch(swizzleR)
262 	{
263 	case GL_RED:
264 	case GL_GREEN:
265 	case GL_BLUE:
266 	case GL_ALPHA:
267 	case GL_ZERO:
268 	case GL_ONE:
269 		mSwizzleR = swizzleR;
270 		return true;
271 	default:
272 		return false;
273 	}
274 }
275 
setSwizzleG(GLenum swizzleG)276 bool Texture::setSwizzleG(GLenum swizzleG)
277 {
278 	switch(swizzleG)
279 	{
280 	case GL_RED:
281 	case GL_GREEN:
282 	case GL_BLUE:
283 	case GL_ALPHA:
284 	case GL_ZERO:
285 	case GL_ONE:
286 		mSwizzleG = swizzleG;
287 		return true;
288 	default:
289 		return false;
290 	}
291 }
292 
setSwizzleB(GLenum swizzleB)293 bool Texture::setSwizzleB(GLenum swizzleB)
294 {
295 	switch(swizzleB)
296 	{
297 	case GL_RED:
298 	case GL_GREEN:
299 	case GL_BLUE:
300 	case GL_ALPHA:
301 	case GL_ZERO:
302 	case GL_ONE:
303 		mSwizzleB = swizzleB;
304 		return true;
305 	default:
306 		return false;
307 	}
308 }
309 
setSwizzleA(GLenum swizzleA)310 bool Texture::setSwizzleA(GLenum swizzleA)
311 {
312 	switch(swizzleA)
313 	{
314 	case GL_RED:
315 	case GL_GREEN:
316 	case GL_BLUE:
317 	case GL_ALPHA:
318 	case GL_ZERO:
319 	case GL_ONE:
320 		mSwizzleA = swizzleA;
321 		return true;
322 	default:
323 		return false;
324 	}
325 }
326 
getDepth(GLenum target,GLint level) const327 GLsizei Texture::getDepth(GLenum target, GLint level) const
328 {
329 	return 1;
330 }
331 
createSharedImage(GLenum target,unsigned int level)332 egl::Image *Texture::createSharedImage(GLenum target, unsigned int level)
333 {
334 	egl::Image *image = getRenderTarget(target, level);   // Increments reference count
335 
336 	if(image)
337 	{
338 		image->markShared();
339 	}
340 
341 	return image;
342 }
343 
setImage(GLenum format,GLenum type,const gl::PixelStorageModes & unpackParameters,const void * pixels,egl::Image * image)344 void Texture::setImage(GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels, egl::Image *image)
345 {
346 	if(pixels && image)
347 	{
348 		GLsizei depth = (getTarget() == GL_TEXTURE_3D_OES || getTarget() == GL_TEXTURE_2D_ARRAY) ? image->getDepth() : 1;
349 		image->loadImageData(0, 0, 0, image->getWidth(), image->getHeight(), depth, format, type, unpackParameters, pixels);
350 	}
351 }
352 
setCompressedImage(GLsizei imageSize,const void * pixels,egl::Image * image)353 void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, egl::Image *image)
354 {
355 	if(pixels && image && (imageSize > 0)) // imageSize's correlation to width and height is already validated with gl::ComputeCompressedSize() at the API level
356 	{
357 		GLsizei depth = (getTarget() == GL_TEXTURE_3D_OES || getTarget() == GL_TEXTURE_2D_ARRAY) ? image->getDepth() : 1;
358 		image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), depth, imageSize, pixels);
359 	}
360 }
361 
subImage(GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,const gl::PixelStorageModes & unpackParameters,const void * pixels,egl::Image * image)362 void Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels, egl::Image *image)
363 {
364 	if(!image)
365 	{
366 		return error(GL_INVALID_OPERATION);
367 	}
368 
369 	if(pixels && width > 0 && height > 0 && depth > 0)
370 	{
371 		image->loadImageData(xoffset, yoffset, zoffset, width, height, depth, format, type, unpackParameters, pixels);
372 	}
373 }
374 
subImageCompressed(GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLsizei imageSize,const void * pixels,egl::Image * image)375 void Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels, egl::Image *image)
376 {
377 	if(!image)
378 	{
379 		return error(GL_INVALID_OPERATION);
380 	}
381 
382 	if(pixels && (imageSize > 0)) // imageSize's correlation to width and height is already validated with gl::ComputeCompressedSize() at the API level
383 	{
384 		image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, imageSize, pixels);
385 	}
386 }
387 
copy(egl::Image * source,const sw::SliceRect & sourceRect,GLint xoffset,GLint yoffset,GLint zoffset,egl::Image * dest)388 bool Texture::copy(egl::Image *source, const sw::SliceRect &sourceRect, GLint xoffset, GLint yoffset, GLint zoffset, egl::Image *dest)
389 {
390 	Device *device = getDevice();
391 
392 	sw::SliceRect destRect(xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0), zoffset);
393 	sw::SliceRectF sourceRectF(static_cast<float>(sourceRect.x0),
394 	                           static_cast<float>(sourceRect.y0),
395 	                           static_cast<float>(sourceRect.x1),
396 	                           static_cast<float>(sourceRect.y1),
397 	                           sourceRect.slice);
398 	bool success = device->stretchRect(source, &sourceRectF, dest, &destRect, Device::ALL_BUFFERS);
399 
400 	if(!success)
401 	{
402 		return error(GL_OUT_OF_MEMORY, false);
403 	}
404 
405 	return true;
406 }
407 
isMipmapFiltered(Sampler * sampler) const408 bool Texture::isMipmapFiltered(Sampler *sampler) const
409 {
410 	GLenum minFilter = sampler ? sampler->getMinFilter() : mMinFilter;
411 
412 	switch(minFilter)
413 	{
414 	case GL_NEAREST:
415 	case GL_LINEAR:
416 		return false;
417 	case GL_NEAREST_MIPMAP_NEAREST:
418 	case GL_LINEAR_MIPMAP_NEAREST:
419 	case GL_NEAREST_MIPMAP_LINEAR:
420 	case GL_LINEAR_MIPMAP_LINEAR:
421 		return true;
422 	default: UNREACHABLE(minFilter);
423 	}
424 
425 	return false;
426 }
427 
Texture2D(GLuint name)428 Texture2D::Texture2D(GLuint name) : Texture(name)
429 {
430 	mSurface = nullptr;
431 
432 	mColorbufferProxy = nullptr;
433 	mProxyRefs = 0;
434 }
435 
~Texture2D()436 Texture2D::~Texture2D()
437 {
438 	image.unbind(this);
439 
440 	if(mSurface)
441 	{
442 		mSurface->setBoundTexture(nullptr);
443 		mSurface = nullptr;
444 	}
445 
446 	mColorbufferProxy = nullptr;
447 }
448 
449 // We need to maintain a count of references to renderbuffers acting as
450 // proxies for this texture, so that we do not attempt to use a pointer
451 // to a renderbuffer proxy which has been deleted.
addProxyRef(const Renderbuffer * proxy)452 void Texture2D::addProxyRef(const Renderbuffer *proxy)
453 {
454 	mProxyRefs++;
455 }
456 
releaseProxy(const Renderbuffer * proxy)457 void Texture2D::releaseProxy(const Renderbuffer *proxy)
458 {
459 	if(mProxyRefs > 0)
460 	{
461 		mProxyRefs--;
462 	}
463 
464 	if(mProxyRefs == 0)
465 	{
466 		mColorbufferProxy = nullptr;
467 	}
468 }
469 
sweep()470 void Texture2D::sweep()
471 {
472 	int imageCount = 0;
473 
474 	for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
475 	{
476 		if(image[i] && image[i]->isChildOf(this))
477 		{
478 			if(!image[i]->hasSingleReference())
479 			{
480 				return;
481 			}
482 
483 			imageCount++;
484 		}
485 	}
486 
487 	if(imageCount == referenceCount)
488 	{
489 		destroy();
490 	}
491 }
492 
getTarget() const493 GLenum Texture2D::getTarget() const
494 {
495 	return GL_TEXTURE_2D;
496 }
497 
getWidth(GLenum target,GLint level) const498 GLsizei Texture2D::getWidth(GLenum target, GLint level) const
499 {
500 	ASSERT(target == getTarget());
501 	return image[level] ? image[level]->getWidth() : 0;
502 }
503 
getHeight(GLenum target,GLint level) const504 GLsizei Texture2D::getHeight(GLenum target, GLint level) const
505 {
506 	ASSERT(target == getTarget());
507 	return image[level] ? image[level]->getHeight() : 0;
508 }
509 
getFormat(GLenum target,GLint level) const510 GLint Texture2D::getFormat(GLenum target, GLint level) const
511 {
512 	ASSERT(target == getTarget());
513 	return image[level] ? image[level]->getFormat() : GL_NONE;
514 }
515 
getTopLevel() const516 int Texture2D::getTopLevel() const
517 {
518 	int level = mBaseLevel;
519 
520 	while(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[level])
521 	{
522 		level++;
523 	}
524 
525 	return level - 1;
526 }
527 
requiresSync() const528 bool Texture2D::requiresSync() const
529 {
530 	for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
531 	{
532 		if(image[level] && image[level]->requiresSync())
533 		{
534 			return true;
535 		}
536 	}
537 
538 	return false;
539 }
540 
setImage(GLint level,GLsizei width,GLsizei height,GLint internalformat,GLenum format,GLenum type,const gl::PixelStorageModes & unpackParameters,const void * pixels)541 void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels)
542 {
543 	if(image[level])
544 	{
545 		image[level]->release();
546 	}
547 
548 	image[level] = egl::Image::create(this, width, height, internalformat);
549 
550 	if(!image[level])
551 	{
552 		return error(GL_OUT_OF_MEMORY);
553 	}
554 
555 	Texture::setImage(format, type, unpackParameters, pixels, image[level]);
556 }
557 
bindTexImage(gl::Surface * surface)558 void Texture2D::bindTexImage(gl::Surface *surface)
559 {
560 	image.release();
561 
562 	image[0] = surface->getRenderTarget();
563 
564 	mSurface = surface;
565 	mSurface->setBoundTexture(this);
566 }
567 
releaseTexImage()568 void Texture2D::releaseTexImage()
569 {
570 	image.release();
571 
572 	if(mSurface)
573 	{
574 		mSurface->setBoundTexture(nullptr);
575 		mSurface = nullptr;
576 	}
577 }
578 
setCompressedImage(GLint level,GLenum format,GLsizei width,GLsizei height,GLsizei imageSize,const void * pixels)579 void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
580 {
581 	if(image[level])
582 	{
583 		image[level]->release();
584 	}
585 
586 	image[level] = egl::Image::create(this, width, height, format);
587 
588 	if(!image[level])
589 	{
590 		return error(GL_OUT_OF_MEMORY);
591 	}
592 
593 	Texture::setCompressedImage(imageSize, pixels, image[level]);
594 }
595 
subImage(GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,const gl::PixelStorageModes & unpackParameters,const void * pixels)596 void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels)
597 {
598 	Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackParameters, pixels, image[level]);
599 }
600 
subImageCompressed(GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLsizei imageSize,const void * pixels)601 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
602 {
603 	Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, image[level]);
604 }
605 
copyImage(GLint level,GLenum internalformat,GLint x,GLint y,GLsizei width,GLsizei height,Renderbuffer * source)606 void Texture2D::copyImage(GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
607 {
608 	if(image[level])
609 	{
610 		image[level]->release();
611 	}
612 
613 	image[level] = egl::Image::create(this, width, height, internalformat);
614 
615 	if(!image[level])
616 	{
617 		return error(GL_OUT_OF_MEMORY);
618 	}
619 
620 	if(width != 0 && height != 0)
621 	{
622 		egl::Image *renderTarget = source->getRenderTarget();
623 
624 		if(!renderTarget)
625 		{
626 			ERR("Failed to retrieve the render target.");
627 			return error(GL_OUT_OF_MEMORY);
628 		}
629 
630 		sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
631 		sourceRect.clip(0, 0, renderTarget->getWidth(), renderTarget->getHeight());
632 
633 		copy(renderTarget, sourceRect, 0, 0, 0, image[level]);
634 
635 		renderTarget->release();
636 	}
637 }
638 
copySubImage(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLint x,GLint y,GLsizei width,GLsizei height,Renderbuffer * source)639 void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
640 {
641 	if(!image[level])
642 	{
643 		return error(GL_INVALID_OPERATION);
644 	}
645 
646 	if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight() || zoffset != 0)
647 	{
648 		return error(GL_INVALID_VALUE);
649 	}
650 
651 	if(width > 0 && height > 0)
652 	{
653 		egl::Image *renderTarget = source->getRenderTarget();
654 
655 		if(!renderTarget)
656 		{
657 			ERR("Failed to retrieve the render target.");
658 			return error(GL_OUT_OF_MEMORY);
659 		}
660 
661 		sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
662 		sourceRect.clip(0, 0, renderTarget->getWidth(), renderTarget->getHeight());
663 
664 		copy(renderTarget, sourceRect, xoffset, yoffset, zoffset, image[level]);
665 
666 		renderTarget->release();
667 	}
668 }
669 
setSharedImage(egl::Image * sharedImage)670 void Texture2D::setSharedImage(egl::Image *sharedImage)
671 {
672 	if(sharedImage == image[0])
673 	{
674 		return;
675 	}
676 
677 	sharedImage->addRef();
678 
679 	if(image[0])
680 	{
681 		image[0]->release();
682 	}
683 
684 	image[0] = sharedImage;
685 }
686 
687 // Tests for 2D texture sampling completeness. [OpenGL ES 3.0.5] section 3.8.13 page 160.
isSamplerComplete(Sampler * sampler) const688 bool Texture2D::isSamplerComplete(Sampler *sampler) const
689 {
690 	if(!image[mBaseLevel])
691 	{
692 		return false;
693 	}
694 
695 	GLsizei width = image[mBaseLevel]->getWidth();
696 	GLsizei height = image[mBaseLevel]->getHeight();
697 
698 	if(width <= 0 || height <= 0)
699 	{
700 		return false;
701 	}
702 
703 	if(isMipmapFiltered(sampler))
704 	{
705 		if(!isMipmapComplete())
706 		{
707 			return false;
708 		}
709 	}
710 
711 	return true;
712 }
713 
714 // Tests for 2D texture (mipmap) completeness. [OpenGL ES 3.0.5] section 3.8.13 page 160.
isMipmapComplete() const715 bool Texture2D::isMipmapComplete() const
716 {
717 	if(mBaseLevel > mMaxLevel)
718 	{
719 		return false;
720 	}
721 
722 	GLsizei width = image[mBaseLevel]->getWidth();
723 	GLsizei height = image[mBaseLevel]->getHeight();
724 	int maxsize = std::max(width, height);
725 	int p = log2(maxsize) + mBaseLevel;
726 	int q = std::min(p, mMaxLevel);
727 
728 	for(int level = mBaseLevel + 1; level <= q; level++)
729 	{
730 		if(!image[level])
731 		{
732 			return false;
733 		}
734 
735 		if(image[level]->getFormat() != image[mBaseLevel]->getFormat())
736 		{
737 			return false;
738 		}
739 
740 		int i = level - mBaseLevel;
741 
742 		if(image[level]->getWidth() != std::max(1, width >> i))
743 		{
744 			return false;
745 		}
746 
747 		if(image[level]->getHeight() != std::max(1, height >> i))
748 		{
749 			return false;
750 		}
751 	}
752 
753 	return true;
754 }
755 
isCompressed(GLenum target,GLint level) const756 bool Texture2D::isCompressed(GLenum target, GLint level) const
757 {
758 	return IsCompressed(getFormat(target, level));
759 }
760 
isDepth(GLenum target,GLint level) const761 bool Texture2D::isDepth(GLenum target, GLint level) const
762 {
763 	return IsDepthTexture(getFormat(target, level));
764 }
765 
generateMipmaps()766 void Texture2D::generateMipmaps()
767 {
768 	if(!image[mBaseLevel])
769 	{
770 		return;   // Image unspecified. Not an error.
771 	}
772 
773 	if(image[mBaseLevel]->getWidth() == 0 || image[mBaseLevel]->getHeight() == 0)
774 	{
775 		return;   // Zero dimension. Not an error.
776 	}
777 
778 	int maxsize = std::max(image[mBaseLevel]->getWidth(), image[mBaseLevel]->getHeight());
779 	int p = log2(maxsize) + mBaseLevel;
780 	int q = std::min(p, mMaxLevel);
781 
782 	for(int i = mBaseLevel + 1; i <= q; i++)
783 	{
784 		if(image[i])
785 		{
786 			image[i]->release();
787 		}
788 
789 		image[i] = egl::Image::create(this, std::max(image[mBaseLevel]->getWidth() >> i, 1), std::max(image[mBaseLevel]->getHeight() >> i, 1), image[mBaseLevel]->getFormat());
790 
791 		if(!image[i])
792 		{
793 			return error(GL_OUT_OF_MEMORY);
794 		}
795 
796 		getDevice()->stretchRect(image[i - 1], 0, image[i], 0, Device::ALL_BUFFERS | Device::USE_FILTER);
797 	}
798 }
799 
getImage(unsigned int level)800 egl::Image *Texture2D::getImage(unsigned int level)
801 {
802 	return image[level];
803 }
804 
getRenderbuffer(GLenum target,GLint level)805 Renderbuffer *Texture2D::getRenderbuffer(GLenum target, GLint level)
806 {
807 	if(target != getTarget())
808 	{
809 		return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
810 	}
811 
812 	if(!mColorbufferProxy)
813 	{
814 		mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture2D(this, level));
815 	}
816 	else
817 	{
818 		mColorbufferProxy->setLevel(level);
819 	}
820 
821 	return mColorbufferProxy;
822 }
823 
getRenderTarget(GLenum target,unsigned int level)824 egl::Image *Texture2D::getRenderTarget(GLenum target, unsigned int level)
825 {
826 	ASSERT(target == getTarget());
827 	ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
828 
829 	if(image[level])
830 	{
831 		image[level]->addRef();
832 	}
833 
834 	return image[level];
835 }
836 
isShared(GLenum target,unsigned int level) const837 bool Texture2D::isShared(GLenum target, unsigned int level) const
838 {
839 	ASSERT(target == getTarget());
840 	ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
841 
842 	if(mSurface)   // Bound to an EGLSurface
843 	{
844 		return true;
845 	}
846 
847 	if(!image[level])
848 	{
849 		return false;
850 	}
851 
852 	return image[level]->isShared();
853 }
854 
Texture2DRect(GLuint name)855 Texture2DRect::Texture2DRect(GLuint name) : Texture2D(name)
856 {
857 	mMinFilter = GL_LINEAR;
858 	mMagFilter = GL_LINEAR;
859 	mWrapS = GL_CLAMP_TO_EDGE;
860 	mWrapT = GL_CLAMP_TO_EDGE;
861 	mWrapR = GL_CLAMP_TO_EDGE;
862 }
863 
getTarget() const864 GLenum Texture2DRect::getTarget() const
865 {
866 	return GL_TEXTURE_RECTANGLE_ARB;
867 }
868 
getRenderbuffer(GLenum target,GLint level)869 Renderbuffer *Texture2DRect::getRenderbuffer(GLenum target, GLint level)
870 {
871 	if((target != getTarget()) || (level != 0))
872 	{
873 		return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
874 	}
875 
876 	if(!mColorbufferProxy)
877 	{
878 		mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture2DRect(this));
879 	}
880 
881 	return mColorbufferProxy;
882 }
883 
TextureCubeMap(GLuint name)884 TextureCubeMap::TextureCubeMap(GLuint name) : Texture(name)
885 {
886 	for(int f = 0; f < 6; f++)
887 	{
888 		mFaceProxies[f] = nullptr;
889 		mFaceProxyRefs[f] = 0;
890 	}
891 }
892 
~TextureCubeMap()893 TextureCubeMap::~TextureCubeMap()
894 {
895 	for(int i = 0; i < 6; i++)
896 	{
897 		image[i].unbind(this);
898 		mFaceProxies[i] = nullptr;
899 	}
900 }
901 
902 // We need to maintain a count of references to renderbuffers acting as
903 // proxies for this texture, so that the texture is not deleted while
904 // proxy references still exist. If the reference count drops to zero,
905 // we set our proxy pointer null, so that a new attempt at referencing
906 // will cause recreation.
addProxyRef(const Renderbuffer * proxy)907 void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
908 {
909 	for(int f = 0; f < 6; f++)
910 	{
911 		if(mFaceProxies[f] == proxy)
912 		{
913 			mFaceProxyRefs[f]++;
914 		}
915 	}
916 }
917 
releaseProxy(const Renderbuffer * proxy)918 void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
919 {
920 	for(int f = 0; f < 6; f++)
921 	{
922 		if(mFaceProxies[f] == proxy)
923 		{
924 			if(mFaceProxyRefs[f] > 0)
925 			{
926 				mFaceProxyRefs[f]--;
927 			}
928 
929 			if(mFaceProxyRefs[f] == 0)
930 			{
931 				mFaceProxies[f] = nullptr;
932 			}
933 		}
934 	}
935 }
936 
sweep()937 void TextureCubeMap::sweep()
938 {
939 	int imageCount = 0;
940 
941 	for(int f = 0; f < 6; f++)
942 	{
943 		for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
944 		{
945 			if(image[f][i] && image[f][i]->isChildOf(this))
946 			{
947 				if(!image[f][i]->hasSingleReference())
948 				{
949 					return;
950 				}
951 
952 				imageCount++;
953 			}
954 		}
955 	}
956 
957 	if(imageCount == referenceCount)
958 	{
959 		destroy();
960 	}
961 }
962 
getTarget() const963 GLenum TextureCubeMap::getTarget() const
964 {
965 	return GL_TEXTURE_CUBE_MAP;
966 }
967 
getWidth(GLenum target,GLint level) const968 GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
969 {
970 	int face = CubeFaceIndex(target);
971 	return image[face][level] ? image[face][level]->getWidth() : 0;
972 }
973 
getHeight(GLenum target,GLint level) const974 GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
975 {
976 	int face = CubeFaceIndex(target);
977 	return image[face][level] ? image[face][level]->getHeight() : 0;
978 }
979 
getFormat(GLenum target,GLint level) const980 GLint TextureCubeMap::getFormat(GLenum target, GLint level) const
981 {
982 	int face = CubeFaceIndex(target);
983 	return image[face][level] ? image[face][level]->getFormat() : 0;
984 }
985 
getTopLevel() const986 int TextureCubeMap::getTopLevel() const
987 {
988 	int level = mBaseLevel;
989 
990 	while(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[0][level])
991 	{
992 		level++;
993 	}
994 
995 	return level - 1;
996 }
997 
requiresSync() const998 bool TextureCubeMap::requiresSync() const
999 {
1000 	for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1001 	{
1002 		for(int face = 0; face < 6; face++)
1003 		{
1004 			if(image[face][level] && image[face][level]->requiresSync())
1005 			{
1006 				return true;
1007 			}
1008 		}
1009 	}
1010 
1011 	return false;
1012 }
1013 
setCompressedImage(GLenum target,GLint level,GLenum format,GLsizei width,GLsizei height,GLsizei imageSize,const void * pixels)1014 void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1015 {
1016 	int face = CubeFaceIndex(target);
1017 
1018 	if(image[face][level])
1019 	{
1020 		image[face][level]->release();
1021 	}
1022 
1023 	image[face][level] = egl::Image::create(this, width, height, 1, 1, format);
1024 
1025 	if(!image[face][level])
1026 	{
1027 		return error(GL_OUT_OF_MEMORY);
1028 	}
1029 
1030 	Texture::setCompressedImage(imageSize, pixels, image[face][level]);
1031 }
1032 
subImage(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,const gl::PixelStorageModes & unpackParameters,const void * pixels)1033 void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels)
1034 {
1035 	Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackParameters, pixels, image[CubeFaceIndex(target)][level]);
1036 }
1037 
subImageCompressed(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLsizei imageSize,const void * pixels)1038 void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1039 {
1040 	Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, image[CubeFaceIndex(target)][level]);
1041 }
1042 
1043 // Tests for cube map sampling completeness. [OpenGL ES 3.0.5] section 3.8.13 page 161.
isSamplerComplete(Sampler * sampler) const1044 bool TextureCubeMap::isSamplerComplete(Sampler *sampler) const
1045 {
1046 	for(int face = 0; face < 6; face++)
1047 	{
1048 		if(!image[face][mBaseLevel])
1049 		{
1050 			return false;
1051 		}
1052 	}
1053 
1054 	int size = image[0][mBaseLevel]->getWidth();
1055 
1056 	if(size <= 0)
1057 	{
1058 		return false;
1059 	}
1060 
1061 	if(!isMipmapFiltered(sampler))
1062 	{
1063 		if(!isCubeComplete())
1064 		{
1065 			return false;
1066 		}
1067 	}
1068 	else
1069 	{
1070 		if(!isMipmapCubeComplete())   // Also tests for isCubeComplete()
1071 		{
1072 			return false;
1073 		}
1074 	}
1075 
1076 	return true;
1077 }
1078 
1079 // Tests for cube texture completeness. [OpenGL ES 3.0.5] section 3.8.13 page 160.
isCubeComplete() const1080 bool TextureCubeMap::isCubeComplete() const
1081 {
1082 	if(image[0][mBaseLevel]->getWidth() <= 0 || image[0][mBaseLevel]->getHeight() != image[0][mBaseLevel]->getWidth())
1083 	{
1084 		return false;
1085 	}
1086 
1087 	for(unsigned int face = 1; face < 6; face++)
1088 	{
1089 		if(image[face][mBaseLevel]->getWidth()  != image[0][mBaseLevel]->getWidth() ||
1090 		   image[face][mBaseLevel]->getWidth()  != image[0][mBaseLevel]->getHeight() ||
1091 		   image[face][mBaseLevel]->getFormat() != image[0][mBaseLevel]->getFormat())
1092 		{
1093 			return false;
1094 		}
1095 	}
1096 
1097 	return true;
1098 }
1099 
isMipmapCubeComplete() const1100 bool TextureCubeMap::isMipmapCubeComplete() const
1101 {
1102 	if(mBaseLevel > mMaxLevel)
1103 	{
1104 		return false;
1105 	}
1106 
1107 	if(!isCubeComplete())
1108 	{
1109 		return false;
1110 	}
1111 
1112 	GLsizei size = image[0][mBaseLevel]->getWidth();
1113 	int p = log2(size) + mBaseLevel;
1114 	int q = std::min(p, mMaxLevel);
1115 
1116 	for(int face = 0; face < 6; face++)
1117 	{
1118 		for(int level = mBaseLevel + 1; level <= q; level++)
1119 		{
1120 			if(!image[face][level])
1121 			{
1122 				return false;
1123 			}
1124 
1125 			if(image[face][level]->getFormat() != image[0][mBaseLevel]->getFormat())
1126 			{
1127 				return false;
1128 			}
1129 
1130 			int i = level - mBaseLevel;
1131 
1132 			if(image[face][level]->getWidth() != std::max(1, size >> i))
1133 			{
1134 				return false;
1135 			}
1136 		}
1137 	}
1138 
1139 	return true;
1140 }
1141 
updateBorders(int level)1142 void TextureCubeMap::updateBorders(int level)
1143 {
1144 	egl::Image *posX = image[CubeFaceIndex(GL_TEXTURE_CUBE_MAP_POSITIVE_X)][level];
1145 	egl::Image *negX = image[CubeFaceIndex(GL_TEXTURE_CUBE_MAP_NEGATIVE_X)][level];
1146 	egl::Image *posY = image[CubeFaceIndex(GL_TEXTURE_CUBE_MAP_POSITIVE_Y)][level];
1147 	egl::Image *negY = image[CubeFaceIndex(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y)][level];
1148 	egl::Image *posZ = image[CubeFaceIndex(GL_TEXTURE_CUBE_MAP_POSITIVE_Z)][level];
1149 	egl::Image *negZ = image[CubeFaceIndex(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)][level];
1150 
1151 	if(!posX || !negX || !posY || !negY || !posZ || !negZ)
1152 	{
1153 		return;
1154 	}
1155 
1156 	if(posX->getBorder() == 0)   // Non-seamless cube map.
1157 	{
1158 		return;
1159 	}
1160 
1161 	if(!posX->hasDirtyContents() || !posY->hasDirtyContents() || !posZ->hasDirtyContents() || !negX->hasDirtyContents() || !negY->hasDirtyContents() || !negZ->hasDirtyContents())
1162 	{
1163 		return;
1164 	}
1165 
1166 	// Copy top / bottom first.
1167 	posX->copyCubeEdge(sw::Surface::BOTTOM, negY, sw::Surface::RIGHT);
1168 	posY->copyCubeEdge(sw::Surface::BOTTOM, posZ, sw::Surface::TOP);
1169 	posZ->copyCubeEdge(sw::Surface::BOTTOM, negY, sw::Surface::TOP);
1170 	negX->copyCubeEdge(sw::Surface::BOTTOM, negY, sw::Surface::LEFT);
1171 	negY->copyCubeEdge(sw::Surface::BOTTOM, negZ, sw::Surface::BOTTOM);
1172 	negZ->copyCubeEdge(sw::Surface::BOTTOM, negY, sw::Surface::BOTTOM);
1173 
1174 	posX->copyCubeEdge(sw::Surface::TOP, posY, sw::Surface::RIGHT);
1175 	posY->copyCubeEdge(sw::Surface::TOP, negZ, sw::Surface::TOP);
1176 	posZ->copyCubeEdge(sw::Surface::TOP, posY, sw::Surface::BOTTOM);
1177 	negX->copyCubeEdge(sw::Surface::TOP, posY, sw::Surface::LEFT);
1178 	negY->copyCubeEdge(sw::Surface::TOP, posZ, sw::Surface::BOTTOM);
1179 	negZ->copyCubeEdge(sw::Surface::TOP, posY, sw::Surface::TOP);
1180 
1181 	// Copy left / right after top and bottom are done.
1182 	// The corner colors will be computed assuming top / bottom are already set.
1183 	posX->copyCubeEdge(sw::Surface::RIGHT, negZ, sw::Surface::LEFT);
1184 	posY->copyCubeEdge(sw::Surface::RIGHT, posX, sw::Surface::TOP);
1185 	posZ->copyCubeEdge(sw::Surface::RIGHT, posX, sw::Surface::LEFT);
1186 	negX->copyCubeEdge(sw::Surface::RIGHT, posZ, sw::Surface::LEFT);
1187 	negY->copyCubeEdge(sw::Surface::RIGHT, posX, sw::Surface::BOTTOM);
1188 	negZ->copyCubeEdge(sw::Surface::RIGHT, negX, sw::Surface::LEFT);
1189 
1190 	posX->copyCubeEdge(sw::Surface::LEFT, posZ, sw::Surface::RIGHT);
1191 	posY->copyCubeEdge(sw::Surface::LEFT, negX, sw::Surface::TOP);
1192 	posZ->copyCubeEdge(sw::Surface::LEFT, negX, sw::Surface::RIGHT);
1193 	negX->copyCubeEdge(sw::Surface::LEFT, negZ, sw::Surface::RIGHT);
1194 	negY->copyCubeEdge(sw::Surface::LEFT, negX, sw::Surface::BOTTOM);
1195 	negZ->copyCubeEdge(sw::Surface::LEFT, posX, sw::Surface::RIGHT);
1196 
1197 	posX->markContentsClean();
1198 	posY->markContentsClean();
1199 	posZ->markContentsClean();
1200 	negX->markContentsClean();
1201 	negY->markContentsClean();
1202 	negZ->markContentsClean();
1203 }
1204 
isCompressed(GLenum target,GLint level) const1205 bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1206 {
1207 	return IsCompressed(getFormat(target, level));
1208 }
1209 
isDepth(GLenum target,GLint level) const1210 bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1211 {
1212 	return IsDepthTexture(getFormat(target, level));
1213 }
1214 
releaseTexImage()1215 void TextureCubeMap::releaseTexImage()
1216 {
1217 	UNREACHABLE(0);   // Cube maps cannot have an EGL surface bound as an image
1218 }
1219 
setImage(GLenum target,GLint level,GLsizei width,GLsizei height,GLint internalformat,GLenum format,GLenum type,const gl::PixelStorageModes & unpackParameters,const void * pixels)1220 void TextureCubeMap::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels)
1221 {
1222 	int face = CubeFaceIndex(target);
1223 
1224 	if(image[face][level])
1225 	{
1226 		image[face][level]->release();
1227 	}
1228 
1229 	image[face][level] = egl::Image::create(this, width, height, 1, 1, internalformat);
1230 
1231 	if(!image[face][level])
1232 	{
1233 		return error(GL_OUT_OF_MEMORY);
1234 	}
1235 
1236 	Texture::setImage(format, type, unpackParameters, pixels, image[face][level]);
1237 }
1238 
copyImage(GLenum target,GLint level,GLenum internalformat,GLint x,GLint y,GLsizei width,GLsizei height,Renderbuffer * source)1239 void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
1240 {
1241 	int face = CubeFaceIndex(target);
1242 
1243 	if(image[face][level])
1244 	{
1245 		image[face][level]->release();
1246 	}
1247 
1248 	image[face][level] = egl::Image::create(this, width, height, 1, 1, internalformat);
1249 
1250 	if(!image[face][level])
1251 	{
1252 		return error(GL_OUT_OF_MEMORY);
1253 	}
1254 
1255 	if(width != 0 && height != 0)
1256 	{
1257 		egl::Image *renderTarget = source->getRenderTarget();
1258 
1259 		if(!renderTarget)
1260 		{
1261 			ERR("Failed to retrieve the render target.");
1262 			return error(GL_OUT_OF_MEMORY);
1263 		}
1264 
1265 		sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
1266 		sourceRect.clip(0, 0, renderTarget->getWidth(), renderTarget->getHeight());
1267 
1268 		copy(renderTarget, sourceRect, 0, 0, 0, image[face][level]);
1269 
1270 		renderTarget->release();
1271 	}
1272 }
1273 
getImage(int face,unsigned int level)1274 egl::Image *TextureCubeMap::getImage(int face, unsigned int level)
1275 {
1276 	return image[face][level];
1277 }
1278 
getImage(GLenum face,unsigned int level)1279 egl::Image *TextureCubeMap::getImage(GLenum face, unsigned int level)
1280 {
1281 	return image[CubeFaceIndex(face)][level];
1282 }
1283 
copySubImage(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLint x,GLint y,GLsizei width,GLsizei height,Renderbuffer * source)1284 void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
1285 {
1286 	int face = CubeFaceIndex(target);
1287 
1288 	if(!image[face][level])
1289 	{
1290 		return error(GL_INVALID_OPERATION);
1291 	}
1292 
1293 	GLsizei size = image[face][level]->getWidth();
1294 
1295 	if(xoffset + width > size || yoffset + height > size || zoffset != 0)
1296 	{
1297 		return error(GL_INVALID_VALUE);
1298 	}
1299 
1300 	if(width > 0 && height > 0)
1301 	{
1302 		egl::Image *renderTarget = source->getRenderTarget();
1303 
1304 		if(!renderTarget)
1305 		{
1306 			ERR("Failed to retrieve the render target.");
1307 			return error(GL_OUT_OF_MEMORY);
1308 		}
1309 
1310 		sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
1311 		sourceRect.clip(0, 0, renderTarget->getWidth(), renderTarget->getHeight());
1312 
1313 		copy(renderTarget, sourceRect, xoffset, yoffset, zoffset, image[face][level]);
1314 
1315 		renderTarget->release();
1316 	}
1317 }
1318 
generateMipmaps()1319 void TextureCubeMap::generateMipmaps()
1320 {
1321 	if(!isCubeComplete())
1322 	{
1323 		return error(GL_INVALID_OPERATION);
1324 	}
1325 
1326 	int p = log2(image[0][mBaseLevel]->getWidth()) + mBaseLevel;
1327 	int q = std::min(p, mMaxLevel);
1328 
1329 	for(int f = 0; f < 6; f++)
1330 	{
1331 		ASSERT(image[f][mBaseLevel]);
1332 
1333 		for(int i = mBaseLevel + 1; i <= q; i++)
1334 		{
1335 			if(image[f][i])
1336 			{
1337 				image[f][i]->release();
1338 			}
1339 
1340 			image[f][i] = egl::Image::create(this, std::max(image[f][mBaseLevel]->getWidth() >> i, 1), std::max(image[f][mBaseLevel]->getHeight() >> i, 1), 1, 1, image[f][mBaseLevel]->getFormat());
1341 
1342 			if(!image[f][i])
1343 			{
1344 				return error(GL_OUT_OF_MEMORY);
1345 			}
1346 
1347 			getDevice()->stretchRect(image[f][i - 1], 0, image[f][i], 0, Device::ALL_BUFFERS | Device::USE_FILTER);
1348 		}
1349 	}
1350 }
1351 
getRenderbuffer(GLenum target,GLint level)1352 Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level)
1353 {
1354 	if(!IsCubemapTextureTarget(target))
1355 	{
1356 		return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
1357 	}
1358 
1359 	int face = CubeFaceIndex(target);
1360 
1361 	if(!mFaceProxies[face])
1362 	{
1363 		mFaceProxies[face] = new Renderbuffer(name, new RenderbufferTextureCubeMap(this, target, level));
1364 	}
1365 	else
1366 	{
1367 		mFaceProxies[face]->setLevel(level);
1368 	}
1369 
1370 	return mFaceProxies[face];
1371 }
1372 
getRenderTarget(GLenum target,unsigned int level)1373 egl::Image *TextureCubeMap::getRenderTarget(GLenum target, unsigned int level)
1374 {
1375 	ASSERT(IsCubemapTextureTarget(target));
1376 	ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1377 
1378 	int face = CubeFaceIndex(target);
1379 
1380 	if(image[face][level])
1381 	{
1382 		image[face][level]->addRef();
1383 	}
1384 
1385 	return image[face][level];
1386 }
1387 
isShared(GLenum target,unsigned int level) const1388 bool TextureCubeMap::isShared(GLenum target, unsigned int level) const
1389 {
1390 	ASSERT(IsCubemapTextureTarget(target));
1391 	ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1392 
1393 	int face = CubeFaceIndex(target);
1394 
1395 	if(!image[face][level])
1396 	{
1397 		return false;
1398 	}
1399 
1400 	return image[face][level]->isShared();
1401 }
1402 
Texture3D(GLuint name)1403 Texture3D::Texture3D(GLuint name) : Texture(name)
1404 {
1405 	mSurface = nullptr;
1406 
1407 	mColorbufferProxy = nullptr;
1408 	mProxyRefs = 0;
1409 }
1410 
~Texture3D()1411 Texture3D::~Texture3D()
1412 {
1413 	image.unbind(this);
1414 
1415 	if(mSurface)
1416 	{
1417 		mSurface->setBoundTexture(nullptr);
1418 		mSurface = nullptr;
1419 	}
1420 
1421 	mColorbufferProxy = nullptr;
1422 }
1423 
1424 // We need to maintain a count of references to renderbuffers acting as
1425 // proxies for this texture, so that we do not attempt to use a pointer
1426 // to a renderbuffer proxy which has been deleted.
addProxyRef(const Renderbuffer * proxy)1427 void Texture3D::addProxyRef(const Renderbuffer *proxy)
1428 {
1429 	mProxyRefs++;
1430 }
1431 
releaseProxy(const Renderbuffer * proxy)1432 void Texture3D::releaseProxy(const Renderbuffer *proxy)
1433 {
1434 	if(mProxyRefs > 0)
1435 	{
1436 		mProxyRefs--;
1437 	}
1438 
1439 	if(mProxyRefs == 0)
1440 	{
1441 		mColorbufferProxy = nullptr;
1442 	}
1443 }
1444 
sweep()1445 void Texture3D::sweep()
1446 {
1447 	int imageCount = 0;
1448 
1449 	for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1450 	{
1451 		if(image[i] && image[i]->isChildOf(this))
1452 		{
1453 			if(!image[i]->hasSingleReference())
1454 			{
1455 				return;
1456 			}
1457 
1458 			imageCount++;
1459 		}
1460 	}
1461 
1462 	if(imageCount == referenceCount)
1463 	{
1464 		destroy();
1465 	}
1466 }
1467 
getTarget() const1468 GLenum Texture3D::getTarget() const
1469 {
1470 	return GL_TEXTURE_3D_OES;
1471 }
1472 
getWidth(GLenum target,GLint level) const1473 GLsizei Texture3D::getWidth(GLenum target, GLint level) const
1474 {
1475 	ASSERT(target == getTarget());
1476 	return image[level] ? image[level]->getWidth() : 0;
1477 }
1478 
getHeight(GLenum target,GLint level) const1479 GLsizei Texture3D::getHeight(GLenum target, GLint level) const
1480 {
1481 	ASSERT(target == getTarget());
1482 	return image[level] ? image[level]->getHeight() : 0;
1483 }
1484 
getDepth(GLenum target,GLint level) const1485 GLsizei Texture3D::getDepth(GLenum target, GLint level) const
1486 {
1487 	ASSERT(target == getTarget());
1488 	return image[level] ? image[level]->getDepth() : 0;
1489 }
1490 
getFormat(GLenum target,GLint level) const1491 GLint Texture3D::getFormat(GLenum target, GLint level) const
1492 {
1493 	ASSERT(target == getTarget());
1494 	return image[level] ? image[level]->getFormat() : GL_NONE;
1495 }
1496 
getTopLevel() const1497 int Texture3D::getTopLevel() const
1498 {
1499 	int level = mBaseLevel;
1500 
1501 	while(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[level])
1502 	{
1503 		level++;
1504 	}
1505 
1506 	return level - 1;
1507 }
1508 
requiresSync() const1509 bool Texture3D::requiresSync() const
1510 {
1511 	for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1512 	{
1513 		if(image[level] && image[level]->requiresSync())
1514 		{
1515 			return true;
1516 		}
1517 	}
1518 
1519 	return false;
1520 }
1521 
setImage(GLint level,GLsizei width,GLsizei height,GLsizei depth,GLint internalformat,GLenum format,GLenum type,const gl::PixelStorageModes & unpackParameters,const void * pixels)1522 void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalformat, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels)
1523 {
1524 	if(image[level])
1525 	{
1526 		image[level]->release();
1527 	}
1528 
1529 	image[level] = egl::Image::create(this, width, height, depth, 0, internalformat);
1530 
1531 	if(!image[level])
1532 	{
1533 		return error(GL_OUT_OF_MEMORY);
1534 	}
1535 
1536 	Texture::setImage(format, type, unpackParameters, pixels, image[level]);
1537 }
1538 
releaseTexImage()1539 void Texture3D::releaseTexImage()
1540 {
1541 	UNREACHABLE(0);   // 3D textures cannot have an EGL surface bound as an image
1542 }
1543 
setCompressedImage(GLint level,GLenum format,GLsizei width,GLsizei height,GLsizei depth,GLsizei imageSize,const void * pixels)1544 void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1545 {
1546 	if(image[level])
1547 	{
1548 		image[level]->release();
1549 	}
1550 
1551 	image[level] = egl::Image::create(this, width, height, depth, 0, format);
1552 
1553 	if(!image[level])
1554 	{
1555 		return error(GL_OUT_OF_MEMORY);
1556 	}
1557 
1558 	Texture::setCompressedImage(imageSize, pixels, image[level]);
1559 }
1560 
subImage(GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,const gl::PixelStorageModes & unpackParameters,const void * pixels)1561 void Texture3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels)
1562 {
1563 	Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpackParameters, pixels, image[level]);
1564 }
1565 
subImageCompressed(GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLsizei imageSize,const void * pixels)1566 void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1567 {
1568 	Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, image[level]);
1569 }
1570 
copyImage(GLint level,GLenum internalformat,GLint x,GLint y,GLint z,GLsizei width,GLsizei height,GLsizei depth,Renderbuffer * source)1571 void Texture3D::copyImage(GLint level, GLenum internalformat, GLint x, GLint y, GLint z, GLsizei width, GLsizei height, GLsizei depth, Renderbuffer *source)
1572 {
1573 	if(image[level])
1574 	{
1575 		image[level]->release();
1576 	}
1577 
1578 	image[level] = egl::Image::create(this, width, height, depth, 0, internalformat);
1579 
1580 	if(!image[level])
1581 	{
1582 		return error(GL_OUT_OF_MEMORY);
1583 	}
1584 
1585 	if(width != 0 && height != 0 && depth != 0)
1586 	{
1587 		egl::Image *renderTarget = source->getRenderTarget();
1588 
1589 		if(!renderTarget)
1590 		{
1591 			ERR("Failed to retrieve the render target.");
1592 			return error(GL_OUT_OF_MEMORY);
1593 		}
1594 
1595 		sw::SliceRect sourceRect(x, y, x + width, y + height, z);
1596 		sourceRect.clip(0, 0, renderTarget->getWidth(), renderTarget->getHeight());
1597 
1598 		for(GLint sliceZ = 0; sliceZ < depth; sliceZ++, sourceRect.slice++)
1599 		{
1600 			copy(renderTarget, sourceRect, 0, 0, sliceZ, image[level]);
1601 		}
1602 
1603 		renderTarget->release();
1604 	}
1605 }
1606 
copySubImage(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLint x,GLint y,GLsizei width,GLsizei height,Renderbuffer * source)1607 void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
1608 {
1609 	if(!image[level])
1610 	{
1611 		return error(GL_INVALID_OPERATION);
1612 	}
1613 
1614 	if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight() || zoffset >= image[level]->getDepth())
1615 	{
1616 		return error(GL_INVALID_VALUE);
1617 	}
1618 
1619 	if(width > 0 && height > 0)
1620 	{
1621 		egl::Image *renderTarget = source->getRenderTarget();
1622 
1623 		if(!renderTarget)
1624 		{
1625 			ERR("Failed to retrieve the render target.");
1626 			return error(GL_OUT_OF_MEMORY);
1627 		}
1628 
1629 		sw::SliceRect sourceRect = {x, y, x + width, y + height, 0};
1630 		sourceRect.clip(0, 0, renderTarget->getWidth(), renderTarget->getHeight());
1631 
1632 		copy(renderTarget, sourceRect, xoffset, yoffset, zoffset, image[level]);
1633 
1634 		renderTarget->release();
1635 	}
1636 }
1637 
setSharedImage(egl::Image * sharedImage)1638 void Texture3D::setSharedImage(egl::Image *sharedImage)
1639 {
1640 	sharedImage->addRef();
1641 
1642 	if(image[0])
1643 	{
1644 		image[0]->release();
1645 	}
1646 
1647 	image[0] = sharedImage;
1648 }
1649 
1650 // Tests for 3D texture sampling completeness. [OpenGL ES 3.0.5] section 3.8.13 page 160.
isSamplerComplete(Sampler * sampler) const1651 bool Texture3D::isSamplerComplete(Sampler *sampler) const
1652 {
1653 	if(!image[mBaseLevel])
1654 	{
1655 		return false;
1656 	}
1657 
1658 	GLsizei width = image[mBaseLevel]->getWidth();
1659 	GLsizei height = image[mBaseLevel]->getHeight();
1660 	GLsizei depth = image[mBaseLevel]->getDepth();
1661 
1662 	if(width <= 0 || height <= 0 || depth <= 0)
1663 	{
1664 		return false;
1665 	}
1666 
1667 	if(isMipmapFiltered(sampler))
1668 	{
1669 		if(!isMipmapComplete())
1670 		{
1671 			return false;
1672 		}
1673 	}
1674 
1675 	return true;
1676 }
1677 
1678 // Tests for 3D texture (mipmap) completeness. [OpenGL ES 3.0.5] section 3.8.13 page 160.
isMipmapComplete() const1679 bool Texture3D::isMipmapComplete() const
1680 {
1681 	if(mBaseLevel > mMaxLevel)
1682 	{
1683 		return false;
1684 	}
1685 
1686 	GLsizei width = image[mBaseLevel]->getWidth();
1687 	GLsizei height = image[mBaseLevel]->getHeight();
1688 	GLsizei depth = image[mBaseLevel]->getDepth();
1689 	bool isTexture2DArray = getTarget() == GL_TEXTURE_2D_ARRAY;
1690 
1691 	int maxsize = isTexture2DArray ? std::max(width, height) : std::max(std::max(width, height), depth);
1692 	int p = log2(maxsize) + mBaseLevel;
1693 	int q = std::min(p, mMaxLevel);
1694 
1695 	for(int level = mBaseLevel + 1; level <= q; level++)
1696 	{
1697 		if(!image[level])
1698 		{
1699 			return false;
1700 		}
1701 
1702 		if(image[level]->getFormat() != image[mBaseLevel]->getFormat())
1703 		{
1704 			return false;
1705 		}
1706 
1707 		int i = level - mBaseLevel;
1708 
1709 		if(image[level]->getWidth() != std::max(1, width >> i))
1710 		{
1711 			return false;
1712 		}
1713 
1714 		if(image[level]->getHeight() != std::max(1, height >> i))
1715 		{
1716 			return false;
1717 		}
1718 
1719 		int levelDepth = isTexture2DArray ? depth : std::max(1, depth >> i);
1720 		if(image[level]->getDepth() != levelDepth)
1721 		{
1722 			return false;
1723 		}
1724 	}
1725 
1726 	return true;
1727 }
1728 
isCompressed(GLenum target,GLint level) const1729 bool Texture3D::isCompressed(GLenum target, GLint level) const
1730 {
1731 	return IsCompressed(getFormat(target, level));
1732 }
1733 
isDepth(GLenum target,GLint level) const1734 bool Texture3D::isDepth(GLenum target, GLint level) const
1735 {
1736 	return IsDepthTexture(getFormat(target, level));
1737 }
1738 
generateMipmaps()1739 void Texture3D::generateMipmaps()
1740 {
1741 	if(!image[mBaseLevel])
1742 	{
1743 		return;   // Image unspecified. Not an error.
1744 	}
1745 
1746 	if(image[mBaseLevel]->getWidth() == 0 || image[mBaseLevel]->getHeight() == 0 || image[mBaseLevel]->getDepth() == 0)
1747 	{
1748 		return;   // Zero dimension. Not an error.
1749 	}
1750 
1751 	int maxsize = std::max(std::max(image[mBaseLevel]->getWidth(), image[mBaseLevel]->getHeight()), image[mBaseLevel]->getDepth());
1752 	int p = log2(maxsize) + mBaseLevel;
1753 	int q = std::min(p, mMaxLevel);
1754 
1755 	for(int i = mBaseLevel + 1; i <= q; i++)
1756 	{
1757 		if(image[i])
1758 		{
1759 			image[i]->release();
1760 		}
1761 
1762 		image[i] = egl::Image::create(this, std::max(image[mBaseLevel]->getWidth() >> i, 1), std::max(image[mBaseLevel]->getHeight() >> i, 1), std::max(image[mBaseLevel]->getDepth() >> i, 1), 0, image[mBaseLevel]->getFormat());
1763 
1764 		if(!image[i])
1765 		{
1766 			return error(GL_OUT_OF_MEMORY);
1767 		}
1768 
1769 		getDevice()->stretchCube(image[i - 1], image[i]);
1770 	}
1771 }
1772 
getImage(unsigned int level)1773 egl::Image *Texture3D::getImage(unsigned int level)
1774 {
1775 	return image[level];
1776 }
1777 
getRenderbuffer(GLenum target,GLint level)1778 Renderbuffer *Texture3D::getRenderbuffer(GLenum target, GLint level)
1779 {
1780 	if(target != getTarget())
1781 	{
1782 		return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
1783 	}
1784 
1785 	if(!mColorbufferProxy)
1786 	{
1787 		mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture3D(this, level));
1788 	}
1789 	else
1790 	{
1791 		mColorbufferProxy->setLevel(level);
1792 	}
1793 
1794 	return mColorbufferProxy;
1795 }
1796 
getRenderTarget(GLenum target,unsigned int level)1797 egl::Image *Texture3D::getRenderTarget(GLenum target, unsigned int level)
1798 {
1799 	ASSERT(target == getTarget());
1800 	ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1801 
1802 	if(image[level])
1803 	{
1804 		image[level]->addRef();
1805 	}
1806 
1807 	return image[level];
1808 }
1809 
isShared(GLenum target,unsigned int level) const1810 bool Texture3D::isShared(GLenum target, unsigned int level) const
1811 {
1812 	ASSERT(target == getTarget());
1813 	ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1814 
1815 	if(mSurface)   // Bound to an EGLSurface
1816 	{
1817 		return true;
1818 	}
1819 
1820 	if(!image[level])
1821 	{
1822 		return false;
1823 	}
1824 
1825 	return image[level]->isShared();
1826 }
1827 
Texture2DArray(GLuint name)1828 Texture2DArray::Texture2DArray(GLuint name) : Texture3D(name)
1829 {
1830 }
1831 
~Texture2DArray()1832 Texture2DArray::~Texture2DArray()
1833 {
1834 }
1835 
getTarget() const1836 GLenum Texture2DArray::getTarget() const
1837 {
1838 	return GL_TEXTURE_2D_ARRAY;
1839 }
1840 
generateMipmaps()1841 void Texture2DArray::generateMipmaps()
1842 {
1843 	if(!image[mBaseLevel])
1844 	{
1845 		return;   // Image unspecified. Not an error.
1846 	}
1847 
1848 	if(image[mBaseLevel]->getWidth() == 0 || image[mBaseLevel]->getHeight() == 0 || image[mBaseLevel]->getDepth() == 0)
1849 	{
1850 		return;   // Zero dimension. Not an error.
1851 	}
1852 
1853 	int depth = image[mBaseLevel]->getDepth();
1854 	int maxsize = std::max(image[mBaseLevel]->getWidth(), image[mBaseLevel]->getHeight());
1855 	int p = log2(maxsize) + mBaseLevel;
1856 	int q = std::min(p, mMaxLevel);
1857 
1858 	for(int i = mBaseLevel + 1; i <= q; i++)
1859 	{
1860 		if(image[i])
1861 		{
1862 			image[i]->release();
1863 		}
1864 
1865 		GLsizei w = std::max(image[mBaseLevel]->getWidth() >> i, 1);
1866 		GLsizei h = std::max(image[mBaseLevel]->getHeight() >> i, 1);
1867 		image[i] = egl::Image::create(this, w, h, depth, 0, image[mBaseLevel]->getFormat());
1868 
1869 		if(!image[i])
1870 		{
1871 			return error(GL_OUT_OF_MEMORY);
1872 		}
1873 
1874 		GLsizei srcw = image[i - 1]->getWidth();
1875 		GLsizei srch = image[i - 1]->getHeight();
1876 		for(int z = 0; z < depth; ++z)
1877 		{
1878 			sw::SliceRectF srcRect(0.0f, 0.0f, static_cast<float>(srcw), static_cast<float>(srch), z);
1879 			sw::SliceRect dstRect(0, 0, w, h, z);
1880 			getDevice()->stretchRect(image[i - 1], &srcRect, image[i], &dstRect, Device::ALL_BUFFERS | Device::USE_FILTER);
1881 		}
1882 	}
1883 }
1884 
TextureExternal(GLuint name)1885 TextureExternal::TextureExternal(GLuint name) : Texture2D(name)
1886 {
1887 	mMinFilter = GL_LINEAR;
1888 	mMagFilter = GL_LINEAR;
1889 	mWrapS = GL_CLAMP_TO_EDGE;
1890 	mWrapT = GL_CLAMP_TO_EDGE;
1891 	mWrapR = GL_CLAMP_TO_EDGE;
1892 }
1893 
~TextureExternal()1894 TextureExternal::~TextureExternal()
1895 {
1896 }
1897 
getTarget() const1898 GLenum TextureExternal::getTarget() const
1899 {
1900 	return GL_TEXTURE_EXTERNAL_OES;
1901 }
1902 
1903 }
1904 
createBackBuffer(int width,int height,sw::Format format,int multiSampleDepth)1905 NO_SANITIZE_FUNCTION egl::Image *createBackBuffer(int width, int height, sw::Format format, int multiSampleDepth)
1906 {
1907 	if(width > es2::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE || height > es2::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE)
1908 	{
1909 		ERR("Invalid parameters: %dx%d", width, height);
1910 		return nullptr;
1911 	}
1912 
1913 	GLenum internalformat = sw2es::ConvertBackBufferFormat(format);
1914 
1915 	return egl::Image::create(width, height, internalformat, multiSampleDepth, false);
1916 }
1917 
createBackBufferFromClientBuffer(const egl::ClientBuffer & clientBuffer)1918 NO_SANITIZE_FUNCTION egl::Image *createBackBufferFromClientBuffer(const egl::ClientBuffer& clientBuffer)
1919 {
1920 	if(clientBuffer.getWidth() > es2::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE ||
1921 	   clientBuffer.getHeight() > es2::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE)
1922 	{
1923 		ERR("Invalid parameters: %dx%d", clientBuffer.getWidth(), clientBuffer.getHeight());
1924 		return nullptr;
1925 	}
1926 
1927 	return egl::Image::create(clientBuffer);
1928 }
1929 
createDepthStencil(int width,int height,sw::Format format,int multiSampleDepth)1930 NO_SANITIZE_FUNCTION egl::Image *createDepthStencil(int width, int height, sw::Format format, int multiSampleDepth)
1931 {
1932 	if(width > es2::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE || height > es2::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE)
1933 	{
1934 		ERR("Invalid parameters: %dx%d", width, height);
1935 		return nullptr;
1936 	}
1937 
1938 	bool lockable = true;
1939 
1940 	switch(format)
1941 	{
1942 //	case sw::FORMAT_D15S1:
1943 	case sw::FORMAT_D24S8:
1944 	case sw::FORMAT_D24X8:
1945 //	case sw::FORMAT_D24X4S4:
1946 	case sw::FORMAT_D24FS8:
1947 	case sw::FORMAT_D32:
1948 	case sw::FORMAT_D16:
1949 		lockable = false;
1950 		break;
1951 //	case sw::FORMAT_S8_LOCKABLE:
1952 //	case sw::FORMAT_D16_LOCKABLE:
1953 	case sw::FORMAT_D32F_LOCKABLE:
1954 //	case sw::FORMAT_D32_LOCKABLE:
1955 	case sw::FORMAT_DF24S8:
1956 	case sw::FORMAT_DF16S8:
1957 		lockable = true;
1958 		break;
1959 	default:
1960 		UNREACHABLE(format);
1961 	}
1962 
1963 	GLenum internalformat = sw2es::ConvertDepthStencilFormat(format);
1964 
1965 	egl::Image *surface = egl::Image::create(width, height, internalformat, multiSampleDepth, lockable);
1966 
1967 	if(!surface)
1968 	{
1969 		ERR("Out of memory");
1970 		return nullptr;
1971 	}
1972 
1973 	return surface;
1974 }
1975