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