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