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 "libEGL/Surface.h"
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(GLenum format,GLenum type,const egl::Image::UnpackInfo & unpackInfo,const void * pixels,egl::Image * image)409 void Texture::setImage(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(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(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(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(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, false);
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 	resource->lock(sw::DESTRUCT);
527 
528 	for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
529 	{
530 		if(image[i])
531 		{
532 			image[i]->unbind(this);
533 			image[i] = nullptr;
534 		}
535 	}
536 
537 	resource->unlock();
538 
539 	if(mSurface)
540 	{
541 		mSurface->setBoundTexture(nullptr);
542 		mSurface = nullptr;
543 	}
544 
545 	mColorbufferProxy = nullptr;
546 }
547 
548 // We need to maintain a count of references to renderbuffers acting as
549 // proxies for this texture, so that we do not attempt to use a pointer
550 // to a renderbuffer proxy which has been deleted.
addProxyRef(const Renderbuffer * proxy)551 void Texture2D::addProxyRef(const Renderbuffer *proxy)
552 {
553 	mProxyRefs++;
554 }
555 
releaseProxy(const Renderbuffer * proxy)556 void Texture2D::releaseProxy(const Renderbuffer *proxy)
557 {
558 	if(mProxyRefs > 0)
559 	{
560 		mProxyRefs--;
561 	}
562 
563 	if(mProxyRefs == 0)
564 	{
565 		mColorbufferProxy = nullptr;
566 	}
567 }
568 
sweep()569 void Texture2D::sweep()
570 {
571 	int imageCount = 0;
572 
573 	for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
574 	{
575 		if(image[i] && image[i]->isChildOf(this))
576 		{
577 			if(!image[i]->hasSingleReference())
578 			{
579 				return;
580 			}
581 
582 			imageCount++;
583 		}
584 	}
585 
586 	if(imageCount == referenceCount)
587 	{
588 		destroy();
589 	}
590 }
591 
getTarget() const592 GLenum Texture2D::getTarget() const
593 {
594 	return GL_TEXTURE_2D;
595 }
596 
getWidth(GLenum target,GLint level) const597 GLsizei Texture2D::getWidth(GLenum target, GLint level) const
598 {
599 	ASSERT(target == GL_TEXTURE_2D);
600 	return image[level] ? image[level]->getWidth() : 0;
601 }
602 
getHeight(GLenum target,GLint level) const603 GLsizei Texture2D::getHeight(GLenum target, GLint level) const
604 {
605 	ASSERT(target == GL_TEXTURE_2D);
606 	return image[level] ? image[level]->getHeight() : 0;
607 }
608 
getFormat(GLenum target,GLint level) const609 GLenum Texture2D::getFormat(GLenum target, GLint level) const
610 {
611 	ASSERT(target == GL_TEXTURE_2D);
612 	return image[level] ? image[level]->getFormat() : GL_NONE;
613 }
614 
getType(GLenum target,GLint level) const615 GLenum Texture2D::getType(GLenum target, GLint level) const
616 {
617 	ASSERT(target == GL_TEXTURE_2D);
618 	return image[level] ? image[level]->getType() : GL_NONE;
619 }
620 
getInternalFormat(GLenum target,GLint level) const621 sw::Format Texture2D::getInternalFormat(GLenum target, GLint level) const
622 {
623 	ASSERT(target == GL_TEXTURE_2D);
624 	return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
625 }
626 
getLevelCount() const627 int Texture2D::getLevelCount() const
628 {
629 	ASSERT(isSamplerComplete());
630 	int levels = 0;
631 
632 	while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[levels])
633 	{
634 		levels++;
635 	}
636 
637 	return levels;
638 }
639 
setImage(GLint level,GLsizei width,GLsizei height,GLenum format,GLenum type,const egl::Image::UnpackInfo & unpackInfo,const void * pixels)640 void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
641 {
642 	if(image[level])
643 	{
644 		image[level]->release();
645 	}
646 
647 	image[level] = new egl::Image(this, width, height, format, type);
648 
649 	if(!image[level])
650 	{
651 		return error(GL_OUT_OF_MEMORY);
652 	}
653 
654 	Texture::setImage(format, type, unpackInfo, pixels, image[level]);
655 }
656 
bindTexImage(egl::Surface * surface)657 void Texture2D::bindTexImage(egl::Surface *surface)
658 {
659 	GLenum format;
660 
661 	switch(surface->getInternalFormat())
662 	{
663 	case sw::FORMAT_A8R8G8B8:
664 	case sw::FORMAT_SRGB8_A8:
665 		format = GL_BGRA_EXT;
666 		break;
667 	case sw::FORMAT_A8B8G8R8:
668 		format = GL_RGBA;
669 		break;
670 	case sw::FORMAT_X8B8G8R8:
671 	case sw::FORMAT_X8R8G8B8:
672 	case sw::FORMAT_SRGB8_X8:
673 		format = GL_RGB;
674 		break;
675 	default:
676 		UNIMPLEMENTED();
677 		return;
678 	}
679 
680 	for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
681 	{
682 		if(image[level])
683 		{
684 			image[level]->release();
685 			image[level] = nullptr;
686 		}
687 	}
688 
689 	image[0] = surface->getRenderTarget();
690 
691 	mSurface = surface;
692 	mSurface->setBoundTexture(this);
693 }
694 
releaseTexImage()695 void Texture2D::releaseTexImage()
696 {
697 	for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
698 	{
699 		if(image[level])
700 		{
701 			image[level]->release();
702 			image[level] = nullptr;
703 		}
704 	}
705 }
706 
setCompressedImage(GLint level,GLenum format,GLsizei width,GLsizei height,GLsizei imageSize,const void * pixels)707 void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
708 {
709 	if(image[level])
710 	{
711 		image[level]->release();
712 	}
713 
714 	GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
715 	image[level] = new egl::Image(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
716 
717 	if(!image[level])
718 	{
719 		return error(GL_OUT_OF_MEMORY);
720 	}
721 
722 	Texture::setCompressedImage(imageSize, pixels, image[level]);
723 }
724 
subImage(GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,const egl::Image::UnpackInfo & unpackInfo,const void * pixels)725 void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
726 {
727 	Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackInfo, pixels, image[level]);
728 }
729 
subImageCompressed(GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLsizei imageSize,const void * pixels)730 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
731 {
732 	Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, image[level]);
733 }
734 
copyImage(GLint level,GLenum format,GLint x,GLint y,GLsizei width,GLsizei height,Framebuffer * source)735 void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
736 {
737 	egl::Image *renderTarget = source->getRenderTarget(0);
738 
739 	if(!renderTarget)
740 	{
741 		ERR("Failed to retrieve the render target.");
742 		return error(GL_OUT_OF_MEMORY);
743 	}
744 
745 	if(image[level])
746 	{
747 		image[level]->release();
748 	}
749 
750 	GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
751 	image[level] = new egl::Image(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
752 
753 	if(!image[level])
754 	{
755 		return error(GL_OUT_OF_MEMORY);
756 	}
757 
758 	if(width != 0 && height != 0)
759 	{
760 		Renderbuffer* renderbuffer = source->getReadColorbuffer();
761 
762 		if(!renderbuffer)
763 		{
764 			ERR("Failed to retrieve the source colorbuffer.");
765 			return;
766 		}
767 
768 		sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
769 		sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
770 
771 		copy(renderTarget, sourceRect, sizedInternalFormat, 0, 0, 0, image[level]);
772 	}
773 
774 	renderTarget->release();
775 }
776 
copySubImage(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLint x,GLint y,GLsizei width,GLsizei height,Framebuffer * source)777 void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
778 {
779 	if(!image[level])
780 	{
781 		return error(GL_INVALID_OPERATION);
782 	}
783 
784 	if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight() || zoffset != 0)
785 	{
786 		return error(GL_INVALID_VALUE);
787 	}
788 
789 	egl::Image *renderTarget = source->getRenderTarget(0);
790 
791 	if(!renderTarget)
792 	{
793 		ERR("Failed to retrieve the render target.");
794 		return error(GL_OUT_OF_MEMORY);
795 	}
796 
797 	Renderbuffer* renderbuffer = source->getReadColorbuffer();
798 
799 	if(!renderbuffer)
800 	{
801 		ERR("Failed to retrieve the source colorbuffer.");
802 		return;
803 	}
804 
805 	sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
806 	sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
807 
808 	copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, zoffset, image[level]);
809 
810 	renderTarget->release();
811 }
812 
setImage(egl::Image * sharedImage)813 void Texture2D::setImage(egl::Image *sharedImage)
814 {
815 	if(sharedImage == image[0])
816 	{
817 		return;
818 	}
819 
820 	sharedImage->addRef();
821 
822 	if(image[0])
823 	{
824 		image[0]->release();
825 	}
826 
827 	image[0] = sharedImage;
828 }
829 
830 // Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
isSamplerComplete() const831 bool Texture2D::isSamplerComplete() const
832 {
833 	if(!image[0])
834 	{
835 		return false;
836 	}
837 
838 	GLsizei width = image[0]->getWidth();
839 	GLsizei height = image[0]->getHeight();
840 
841 	if(width <= 0 || height <= 0)
842 	{
843 		return false;
844 	}
845 
846 	if(isMipmapFiltered())
847 	{
848 		if(!isMipmapComplete())
849 		{
850 			return false;
851 		}
852 	}
853 
854 	return true;
855 }
856 
857 // Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
isMipmapComplete() const858 bool Texture2D::isMipmapComplete() const
859 {
860 	GLsizei width = image[mBaseLevel]->getWidth();
861 	GLsizei height = image[mBaseLevel]->getHeight();
862 
863 	int q = std::min(log2(std::max(width, height)), mMaxLevel);
864 
865 	for(int level = mBaseLevel + 1; level <= q; level++)
866 	{
867 		if(!image[level])
868 		{
869 			return false;
870 		}
871 
872 		if(image[level]->getFormat() != image[0]->getFormat())
873 		{
874 			return false;
875 		}
876 
877 		if(image[level]->getType() != image[0]->getType())
878 		{
879 			return false;
880 		}
881 
882 		if(image[level]->getWidth() != std::max(1, width >> level))
883 		{
884 			return false;
885 		}
886 
887 		if(image[level]->getHeight() != std::max(1, height >> level))
888 		{
889 			return false;
890 		}
891 	}
892 
893 	return true;
894 }
895 
isCompressed(GLenum target,GLint level) const896 bool Texture2D::isCompressed(GLenum target, GLint level) const
897 {
898 	return IsCompressed(getFormat(target, level), egl::getClientVersion());
899 }
900 
isDepth(GLenum target,GLint level) const901 bool Texture2D::isDepth(GLenum target, GLint level) const
902 {
903 	return IsDepthTexture(getFormat(target, level));
904 }
905 
generateMipmaps()906 void Texture2D::generateMipmaps()
907 {
908 	if(!image[0])
909 	{
910 		return;   // FIXME: error?
911 	}
912 
913 	unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight()));
914 
915 	for(unsigned int i = 1; i <= q; i++)
916 	{
917 		if(image[i])
918 		{
919 			image[i]->release();
920 		}
921 
922 		image[i] = new egl::Image(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), image[0]->getFormat(), image[0]->getType());
923 
924 		if(!image[i])
925 		{
926 			return error(GL_OUT_OF_MEMORY);
927 		}
928 
929 		getDevice()->stretchRect(image[i - 1], 0, image[i], 0, true);
930 	}
931 }
932 
getImage(unsigned int level)933 egl::Image *Texture2D::getImage(unsigned int level)
934 {
935 	return image[level];
936 }
937 
getRenderbuffer(GLenum target,GLint level,GLint layer)938 Renderbuffer *Texture2D::getRenderbuffer(GLenum target, GLint level, GLint layer)
939 {
940 	if(target != GL_TEXTURE_2D)
941 	{
942 		return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
943 	}
944 
945 	if(!mColorbufferProxy)
946 	{
947 		mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture2D(this, level));
948 	}
949 	else
950 	{
951 		mColorbufferProxy->setLevel(level);
952 	}
953 
954 	return mColorbufferProxy;
955 }
956 
getRenderTarget(GLenum target,unsigned int level)957 egl::Image *Texture2D::getRenderTarget(GLenum target, unsigned int level)
958 {
959 	ASSERT(target == GL_TEXTURE_2D);
960 	ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
961 
962 	if(image[level])
963 	{
964 		image[level]->addRef();
965 	}
966 
967 	return image[level];
968 }
969 
isShared(GLenum target,unsigned int level) const970 bool Texture2D::isShared(GLenum target, unsigned int level) const
971 {
972 	ASSERT(target == GL_TEXTURE_2D);
973 	ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
974 
975 	if(mSurface)   // Bound to an EGLSurface
976 	{
977 		return true;
978 	}
979 
980 	if(!image[level])
981 	{
982 		return false;
983 	}
984 
985 	return image[level]->isShared();
986 }
987 
TextureCubeMap(GLuint name)988 TextureCubeMap::TextureCubeMap(GLuint name) : Texture(name)
989 {
990 	for(int f = 0; f < 6; f++)
991 	{
992 		for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
993 		{
994 			image[f][i] = nullptr;
995 		}
996 	}
997 
998 	for(int f = 0; f < 6; f++)
999 	{
1000 		mFaceProxies[f] = nullptr;
1001 		mFaceProxyRefs[f] = 0;
1002 	}
1003 }
1004 
~TextureCubeMap()1005 TextureCubeMap::~TextureCubeMap()
1006 {
1007 	resource->lock(sw::DESTRUCT);
1008 
1009 	for(int f = 0; f < 6; f++)
1010 	{
1011 		for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1012 		{
1013 			if(image[f][i])
1014 			{
1015 				image[f][i]->unbind(this);
1016 				image[f][i] = nullptr;
1017 			}
1018 		}
1019 	}
1020 
1021 	resource->unlock();
1022 
1023 	for(int i = 0; i < 6; i++)
1024 	{
1025 		mFaceProxies[i] = nullptr;
1026 	}
1027 }
1028 
1029 // We need to maintain a count of references to renderbuffers acting as
1030 // proxies for this texture, so that the texture is not deleted while
1031 // proxy references still exist. If the reference count drops to zero,
1032 // we set our proxy pointer null, so that a new attempt at referencing
1033 // will cause recreation.
addProxyRef(const Renderbuffer * proxy)1034 void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
1035 {
1036 	for(int f = 0; f < 6; f++)
1037 	{
1038 		if(mFaceProxies[f] == proxy)
1039 		{
1040 			mFaceProxyRefs[f]++;
1041 		}
1042 	}
1043 }
1044 
releaseProxy(const Renderbuffer * proxy)1045 void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
1046 {
1047 	for(int f = 0; f < 6; f++)
1048 	{
1049 		if(mFaceProxies[f] == proxy)
1050 		{
1051 			if(mFaceProxyRefs[f] > 0)
1052 			{
1053 				mFaceProxyRefs[f]--;
1054 			}
1055 
1056 			if(mFaceProxyRefs[f] == 0)
1057 			{
1058 				mFaceProxies[f] = nullptr;
1059 			}
1060 		}
1061 	}
1062 }
1063 
sweep()1064 void TextureCubeMap::sweep()
1065 {
1066 	int imageCount = 0;
1067 
1068 	for(int f = 0; f < 6; f++)
1069 	{
1070 		for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1071 		{
1072 			if(image[f][i] && image[f][i]->isChildOf(this))
1073 			{
1074 				if(!image[f][i]->hasSingleReference())
1075 				{
1076 					return;
1077 				}
1078 
1079 				imageCount++;
1080 			}
1081 		}
1082 	}
1083 
1084 	if(imageCount == referenceCount)
1085 	{
1086 		destroy();
1087 	}
1088 }
1089 
getTarget() const1090 GLenum TextureCubeMap::getTarget() const
1091 {
1092 	return GL_TEXTURE_CUBE_MAP;
1093 }
1094 
getWidth(GLenum target,GLint level) const1095 GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1096 {
1097 	int face = CubeFaceIndex(target);
1098 	return image[face][level] ? image[face][level]->getWidth() : 0;
1099 }
1100 
getHeight(GLenum target,GLint level) const1101 GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1102 {
1103 	int face = CubeFaceIndex(target);
1104 	return image[face][level] ? image[face][level]->getHeight() : 0;
1105 }
1106 
getFormat(GLenum target,GLint level) const1107 GLenum TextureCubeMap::getFormat(GLenum target, GLint level) const
1108 {
1109 	int face = CubeFaceIndex(target);
1110 	return image[face][level] ? image[face][level]->getFormat() : 0;
1111 }
1112 
getType(GLenum target,GLint level) const1113 GLenum TextureCubeMap::getType(GLenum target, GLint level) const
1114 {
1115 	int face = CubeFaceIndex(target);
1116 	return image[face][level] ? image[face][level]->getType() : 0;
1117 }
1118 
getInternalFormat(GLenum target,GLint level) const1119 sw::Format TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1120 {
1121 	int face = CubeFaceIndex(target);
1122 	return image[face][level] ? image[face][level]->getInternalFormat() : sw::FORMAT_NULL;
1123 }
1124 
getLevelCount() const1125 int TextureCubeMap::getLevelCount() const
1126 {
1127 	ASSERT(isSamplerComplete());
1128 	int levels = 0;
1129 
1130 	while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[0][levels])
1131 	{
1132 		levels++;
1133 	}
1134 
1135 	return levels;
1136 }
1137 
setCompressedImage(GLenum target,GLint level,GLenum format,GLsizei width,GLsizei height,GLsizei imageSize,const void * pixels)1138 void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1139 {
1140 	int face = CubeFaceIndex(target);
1141 
1142 	if(image[face][level])
1143 	{
1144 		image[face][level]->release();
1145 	}
1146 
1147 	GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1148 	image[face][level] = new egl::Image(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
1149 
1150 	if(!image[face][level])
1151 	{
1152 		return error(GL_OUT_OF_MEMORY);
1153 	}
1154 
1155 	Texture::setCompressedImage(imageSize, pixels, image[face][level]);
1156 }
1157 
subImage(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,const egl::Image::UnpackInfo & unpackInfo,const void * pixels)1158 void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
1159 {
1160 	Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackInfo, pixels, image[CubeFaceIndex(target)][level]);
1161 }
1162 
subImageCompressed(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLsizei imageSize,const void * pixels)1163 void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1164 {
1165 	Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, image[CubeFaceIndex(target)][level]);
1166 }
1167 
1168 // Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
isSamplerComplete() const1169 bool TextureCubeMap::isSamplerComplete() const
1170 {
1171 	for(int face = 0; face < 6; face++)
1172 	{
1173 		if(!image[face][0])
1174 		{
1175 			return false;
1176 		}
1177 	}
1178 
1179 	int size = image[0][0]->getWidth();
1180 
1181 	if(size <= 0)
1182 	{
1183 		return false;
1184 	}
1185 
1186 	if(!isMipmapFiltered())
1187 	{
1188 		if(!isCubeComplete())
1189 		{
1190 			return false;
1191 		}
1192 	}
1193 	else
1194 	{
1195 		if(!isMipmapCubeComplete())   // Also tests for isCubeComplete()
1196 		{
1197 			return false;
1198 		}
1199 	}
1200 
1201 	return true;
1202 }
1203 
1204 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
isCubeComplete() const1205 bool TextureCubeMap::isCubeComplete() const
1206 {
1207 	if(image[0][mBaseLevel]->getWidth() <= 0 || image[0][mBaseLevel]->getHeight() != image[0][mBaseLevel]->getWidth())
1208 	{
1209 		return false;
1210 	}
1211 
1212 	for(unsigned int face = 1; face < 6; face++)
1213 	{
1214 		if(image[face][mBaseLevel]->getWidth()  != image[0][mBaseLevel]->getWidth() ||
1215 		   image[face][mBaseLevel]->getWidth()  != image[0][mBaseLevel]->getHeight() ||
1216 		   image[face][mBaseLevel]->getFormat() != image[0][mBaseLevel]->getFormat() ||
1217 		   image[face][mBaseLevel]->getType()   != image[0][mBaseLevel]->getType())
1218 		{
1219 			return false;
1220 		}
1221 	}
1222 
1223 	return true;
1224 }
1225 
isMipmapCubeComplete() const1226 bool TextureCubeMap::isMipmapCubeComplete() const
1227 {
1228 	if(!isCubeComplete())
1229 	{
1230 		return false;
1231 	}
1232 
1233 	GLsizei size = image[0][mBaseLevel]->getWidth();
1234 	int q = std::min(log2(size), mMaxLevel);
1235 
1236 	for(int face = 0; face < 6; face++)
1237 	{
1238 		for(int level = mBaseLevel + 1; level <= q; level++)
1239 		{
1240 			if(!image[face][level])
1241 			{
1242 				return false;
1243 			}
1244 
1245 			if(image[face][level]->getFormat() != image[0][mBaseLevel]->getFormat())
1246 			{
1247 				return false;
1248 			}
1249 
1250 			if(image[face][level]->getType() != image[0][mBaseLevel]->getType())
1251 			{
1252 				return false;
1253 			}
1254 
1255 			if(image[face][level]->getWidth() != std::max(1, size >> level))
1256 			{
1257 				return false;
1258 			}
1259 		}
1260 	}
1261 
1262 	return true;
1263 }
1264 
isCompressed(GLenum target,GLint level) const1265 bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1266 {
1267 	return IsCompressed(getFormat(target, level), egl::getClientVersion());
1268 }
1269 
isDepth(GLenum target,GLint level) const1270 bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1271 {
1272 	return IsDepthTexture(getFormat(target, level));
1273 }
1274 
releaseTexImage()1275 void TextureCubeMap::releaseTexImage()
1276 {
1277 	UNREACHABLE(0);   // Cube maps cannot have an EGL surface bound as an image
1278 }
1279 
setImage(GLenum target,GLint level,GLsizei width,GLsizei height,GLenum format,GLenum type,const egl::Image::UnpackInfo & unpackInfo,const void * pixels)1280 void TextureCubeMap::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
1281 {
1282 	int face = CubeFaceIndex(target);
1283 
1284 	if(image[face][level])
1285 	{
1286 		image[face][level]->release();
1287 	}
1288 
1289 	image[face][level] = new egl::Image(this, width, height, format, type);
1290 
1291 	if(!image[face][level])
1292 	{
1293 		return error(GL_OUT_OF_MEMORY);
1294 	}
1295 
1296 	Texture::setImage(format, type, unpackInfo, pixels, image[face][level]);
1297 }
1298 
copyImage(GLenum target,GLint level,GLenum format,GLint x,GLint y,GLsizei width,GLsizei height,Framebuffer * source)1299 void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1300 {
1301 	egl::Image *renderTarget = source->getRenderTarget(0);
1302 
1303 	if(!renderTarget)
1304 	{
1305 		ERR("Failed to retrieve the render target.");
1306 		return error(GL_OUT_OF_MEMORY);
1307 	}
1308 
1309 	int face = CubeFaceIndex(target);
1310 
1311 	if(image[face][level])
1312 	{
1313 		image[face][level]->release();
1314 	}
1315 
1316 	GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1317 	image[face][level] = new egl::Image(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
1318 
1319 	if(!image[face][level])
1320 	{
1321 		return error(GL_OUT_OF_MEMORY);
1322 	}
1323 
1324 	if(width != 0 && height != 0)
1325 	{
1326 		Renderbuffer* renderbuffer = source->getReadColorbuffer();
1327 
1328 		if(!renderbuffer)
1329 		{
1330 			ERR("Failed to retrieve the source colorbuffer.");
1331 			return;
1332 		}
1333 
1334 		sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
1335 		sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
1336 
1337 		copy(renderTarget, sourceRect, sizedInternalFormat, 0, 0, 0, image[face][level]);
1338 	}
1339 
1340 	renderTarget->release();
1341 }
1342 
getImage(int face,unsigned int level)1343 egl::Image *TextureCubeMap::getImage(int face, unsigned int level)
1344 {
1345 	return image[face][level];
1346 }
1347 
getImage(GLenum face,unsigned int level)1348 egl::Image *TextureCubeMap::getImage(GLenum face, unsigned int level)
1349 {
1350 	return image[CubeFaceIndex(face)][level];
1351 }
1352 
copySubImage(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLint x,GLint y,GLsizei width,GLsizei height,Framebuffer * source)1353 void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1354 {
1355 	int face = CubeFaceIndex(target);
1356 
1357 	if(!image[face][level])
1358 	{
1359 		return error(GL_INVALID_OPERATION);
1360 	}
1361 
1362 	GLsizei size = image[face][level]->getWidth();
1363 
1364 	if(xoffset + width > size || yoffset + height > size || zoffset != 0)
1365 	{
1366 		return error(GL_INVALID_VALUE);
1367 	}
1368 
1369 	egl::Image *renderTarget = source->getRenderTarget(0);
1370 
1371 	if(!renderTarget)
1372 	{
1373 		ERR("Failed to retrieve the render target.");
1374 		return error(GL_OUT_OF_MEMORY);
1375 	}
1376 
1377 	Renderbuffer* renderbuffer = source->getReadColorbuffer();
1378 
1379 	if(!renderbuffer)
1380 	{
1381 		ERR("Failed to retrieve the source colorbuffer.");
1382 		return;
1383 	}
1384 
1385 	sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
1386 	sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
1387 
1388 	copy(renderTarget, sourceRect, image[face][level]->getFormat(), xoffset, yoffset, zoffset, image[face][level]);
1389 
1390 	renderTarget->release();
1391 }
1392 
generateMipmaps()1393 void TextureCubeMap::generateMipmaps()
1394 {
1395 	if(!isCubeComplete())
1396 	{
1397 		return error(GL_INVALID_OPERATION);
1398 	}
1399 
1400 	unsigned int q = log2(image[0][0]->getWidth());
1401 
1402 	for(unsigned int f = 0; f < 6; f++)
1403 	{
1404 		for(unsigned int i = 1; i <= q; i++)
1405 		{
1406 			if(image[f][i])
1407 			{
1408 				image[f][i]->release();
1409 			}
1410 
1411 			image[f][i] = new egl::Image(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());
1412 
1413 			if(!image[f][i])
1414 			{
1415 				return error(GL_OUT_OF_MEMORY);
1416 			}
1417 
1418 			getDevice()->stretchRect(image[f][i - 1], 0, image[f][i], 0, true);
1419 		}
1420 	}
1421 }
1422 
getRenderbuffer(GLenum target,GLint level,GLint layer)1423 Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level, GLint layer)
1424 {
1425 	if(!IsCubemapTextureTarget(target))
1426 	{
1427 		return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
1428 	}
1429 
1430 	int face = CubeFaceIndex(target);
1431 
1432 	if(!mFaceProxies[face])
1433 	{
1434 		mFaceProxies[face] = new Renderbuffer(name, new RenderbufferTextureCubeMap(this, target, level));
1435 	}
1436 	else
1437 	{
1438 		mFaceProxies[face]->setLevel(level);
1439 	}
1440 
1441 	return mFaceProxies[face];
1442 }
1443 
getRenderTarget(GLenum target,unsigned int level)1444 egl::Image *TextureCubeMap::getRenderTarget(GLenum target, unsigned int level)
1445 {
1446 	ASSERT(IsCubemapTextureTarget(target));
1447 	ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1448 
1449 	int face = CubeFaceIndex(target);
1450 
1451 	if(image[face][level])
1452 	{
1453 		image[face][level]->addRef();
1454 	}
1455 
1456 	return image[face][level];
1457 }
1458 
isShared(GLenum target,unsigned int level) const1459 bool TextureCubeMap::isShared(GLenum target, unsigned int level) const
1460 {
1461 	ASSERT(IsCubemapTextureTarget(target));
1462 	ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1463 
1464 	int face = CubeFaceIndex(target);
1465 
1466 	if(!image[face][level])
1467 	{
1468 		return false;
1469 	}
1470 
1471 	return image[face][level]->isShared();
1472 }
1473 
Texture3D(GLuint name)1474 Texture3D::Texture3D(GLuint name) : Texture(name)
1475 {
1476 	for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1477 	{
1478 		image[i] = nullptr;
1479 	}
1480 
1481 	mSurface = nullptr;
1482 
1483 	mColorbufferProxy = nullptr;
1484 	mProxyRefs = 0;
1485 }
1486 
~Texture3D()1487 Texture3D::~Texture3D()
1488 {
1489 	resource->lock(sw::DESTRUCT);
1490 
1491 	for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1492 	{
1493 		if(image[i])
1494 		{
1495 			image[i]->unbind(this);
1496 			image[i] = nullptr;
1497 		}
1498 	}
1499 
1500 	resource->unlock();
1501 
1502 	if(mSurface)
1503 	{
1504 		mSurface->setBoundTexture(nullptr);
1505 		mSurface = nullptr;
1506 	}
1507 
1508 	mColorbufferProxy = nullptr;
1509 }
1510 
1511 // We need to maintain a count of references to renderbuffers acting as
1512 // proxies for this texture, so that we do not attempt to use a pointer
1513 // to a renderbuffer proxy which has been deleted.
addProxyRef(const Renderbuffer * proxy)1514 void Texture3D::addProxyRef(const Renderbuffer *proxy)
1515 {
1516 	mProxyRefs++;
1517 }
1518 
releaseProxy(const Renderbuffer * proxy)1519 void Texture3D::releaseProxy(const Renderbuffer *proxy)
1520 {
1521 	if(mProxyRefs > 0)
1522 	{
1523 		mProxyRefs--;
1524 	}
1525 
1526 	if(mProxyRefs == 0)
1527 	{
1528 		mColorbufferProxy = nullptr;
1529 	}
1530 }
1531 
sweep()1532 void Texture3D::sweep()
1533 {
1534 	int imageCount = 0;
1535 
1536 	for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1537 	{
1538 		if(image[i] && image[i]->isChildOf(this))
1539 		{
1540 			if(!image[i]->hasSingleReference())
1541 			{
1542 				return;
1543 			}
1544 
1545 			imageCount++;
1546 		}
1547 	}
1548 
1549 	if(imageCount == referenceCount)
1550 	{
1551 		destroy();
1552 	}
1553 }
1554 
getTarget() const1555 GLenum Texture3D::getTarget() const
1556 {
1557 	return GL_TEXTURE_3D_OES;
1558 }
1559 
getWidth(GLenum target,GLint level) const1560 GLsizei Texture3D::getWidth(GLenum target, GLint level) const
1561 {
1562 	ASSERT(target == getTarget());
1563 	return image[level] ? image[level]->getWidth() : 0;
1564 }
1565 
getHeight(GLenum target,GLint level) const1566 GLsizei Texture3D::getHeight(GLenum target, GLint level) const
1567 {
1568 	ASSERT(target == getTarget());
1569 	return image[level] ? image[level]->getHeight() : 0;
1570 }
1571 
getDepth(GLenum target,GLint level) const1572 GLsizei Texture3D::getDepth(GLenum target, GLint level) const
1573 {
1574 	ASSERT(target == getTarget());
1575 	return image[level] ? image[level]->getDepth() : 0;
1576 }
1577 
getFormat(GLenum target,GLint level) const1578 GLenum Texture3D::getFormat(GLenum target, GLint level) const
1579 {
1580 	ASSERT(target == getTarget());
1581 	return image[level] ? image[level]->getFormat() : GL_NONE;
1582 }
1583 
getType(GLenum target,GLint level) const1584 GLenum Texture3D::getType(GLenum target, GLint level) const
1585 {
1586 	ASSERT(target == getTarget());
1587 	return image[level] ? image[level]->getType() : GL_NONE;
1588 }
1589 
getInternalFormat(GLenum target,GLint level) const1590 sw::Format Texture3D::getInternalFormat(GLenum target, GLint level) const
1591 {
1592 	ASSERT(target == getTarget());
1593 	return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
1594 }
1595 
getLevelCount() const1596 int Texture3D::getLevelCount() const
1597 {
1598 	ASSERT(isSamplerComplete());
1599 	int levels = 0;
1600 
1601 	while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[levels])
1602 	{
1603 		levels++;
1604 	}
1605 
1606 	return levels;
1607 }
1608 
setImage(GLint level,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,const egl::Image::UnpackInfo & unpackInfo,const void * pixels)1609 void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
1610 {
1611 	if(image[level])
1612 	{
1613 		image[level]->release();
1614 	}
1615 
1616 	image[level] = new egl::Image(this, width, height, depth, format, type);
1617 
1618 	if(!image[level])
1619 	{
1620 		return error(GL_OUT_OF_MEMORY);
1621 	}
1622 
1623 	Texture::setImage(format, type, unpackInfo, pixels, image[level]);
1624 }
1625 
bindTexImage(egl::Surface * surface)1626 void Texture3D::bindTexImage(egl::Surface *surface)
1627 {
1628 	GLenum format;
1629 
1630 	switch(surface->getInternalFormat())
1631 	{
1632 	case sw::FORMAT_A8R8G8B8:
1633 		format = GL_RGBA;
1634 		break;
1635 	case sw::FORMAT_X8R8G8B8:
1636 		format = GL_RGB;
1637 		break;
1638 	default:
1639 		UNIMPLEMENTED();
1640 		return;
1641 	}
1642 
1643 	for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1644 	{
1645 		if(image[level])
1646 		{
1647 			image[level]->release();
1648 			image[level] = nullptr;
1649 		}
1650 	}
1651 
1652 	image[0] = surface->getRenderTarget();
1653 
1654 	mSurface = surface;
1655 	mSurface->setBoundTexture(this);
1656 }
1657 
releaseTexImage()1658 void Texture3D::releaseTexImage()
1659 {
1660 	for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1661 	{
1662 		if(image[level])
1663 		{
1664 			image[level]->release();
1665 			image[level] = nullptr;
1666 		}
1667 	}
1668 }
1669 
setCompressedImage(GLint level,GLenum format,GLsizei width,GLsizei height,GLsizei depth,GLsizei imageSize,const void * pixels)1670 void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1671 {
1672 	if(image[level])
1673 	{
1674 		image[level]->release();
1675 	}
1676 
1677 	GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1678 	image[level] = new egl::Image(this, width, height, depth, sizedInternalFormat, GL_UNSIGNED_BYTE);
1679 
1680 	if(!image[level])
1681 	{
1682 		return error(GL_OUT_OF_MEMORY);
1683 	}
1684 
1685 	Texture::setCompressedImage(imageSize, pixels, image[level]);
1686 }
1687 
subImage(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)1688 void Texture3D::subImage(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)
1689 {
1690 	Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpackInfo, pixels, image[level]);
1691 }
1692 
subImageCompressed(GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLsizei imageSize,const void * pixels)1693 void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1694 {
1695 	Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, image[level]);
1696 }
1697 
copyImage(GLint level,GLenum format,GLint x,GLint y,GLint z,GLsizei width,GLsizei height,GLsizei depth,Framebuffer * source)1698 void Texture3D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLint z, GLsizei width, GLsizei height, GLsizei depth, Framebuffer *source)
1699 {
1700 	egl::Image *renderTarget = source->getRenderTarget(0);
1701 
1702 	if(!renderTarget)
1703 	{
1704 		ERR("Failed to retrieve the render target.");
1705 		return error(GL_OUT_OF_MEMORY);
1706 	}
1707 
1708 	if(image[level])
1709 	{
1710 		image[level]->release();
1711 	}
1712 
1713 	GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1714 	image[level] = new egl::Image(this, width, height, depth, sizedInternalFormat, GL_UNSIGNED_BYTE);
1715 
1716 	if(!image[level])
1717 	{
1718 		return error(GL_OUT_OF_MEMORY);
1719 	}
1720 
1721 	if(width != 0 && height != 0 && depth != 0)
1722 	{
1723 		Renderbuffer* renderbuffer = source->getReadColorbuffer();
1724 
1725 		if(!renderbuffer)
1726 		{
1727 			ERR("Failed to retrieve the source colorbuffer.");
1728 			return;
1729 		}
1730 
1731 		sw::SliceRect sourceRect(x, y, x + width, y + height, z);
1732 		sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
1733 		for(GLint sliceZ = 0; sliceZ < depth; ++sliceZ, ++sourceRect.slice)
1734 		{
1735 			copy(renderTarget, sourceRect, sizedInternalFormat, 0, 0, sliceZ, image[level]);
1736 		}
1737 	}
1738 
1739 	renderTarget->release();
1740 }
1741 
copySubImage(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLint x,GLint y,GLsizei width,GLsizei height,Framebuffer * source)1742 void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1743 {
1744 	if(!image[level])
1745 	{
1746 		return error(GL_INVALID_OPERATION);
1747 	}
1748 
1749 	if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight() || zoffset >= image[level]->getDepth())
1750 	{
1751 		return error(GL_INVALID_VALUE);
1752 	}
1753 
1754 	egl::Image *renderTarget = source->getRenderTarget(0);
1755 
1756 	if(!renderTarget)
1757 	{
1758 		ERR("Failed to retrieve the render target.");
1759 		return error(GL_OUT_OF_MEMORY);
1760 	}
1761 
1762 	Renderbuffer* renderbuffer = source->getReadColorbuffer();
1763 
1764 	if(!renderbuffer)
1765 	{
1766 		ERR("Failed to retrieve the source colorbuffer.");
1767 		return;
1768 	}
1769 
1770 	sw::SliceRect sourceRect = {x, y, x + width, y + height, 0};
1771 	sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
1772 
1773 	copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, zoffset, image[level]);
1774 
1775 	renderTarget->release();
1776 }
1777 
setImage(egl::Image * sharedImage)1778 void Texture3D::setImage(egl::Image *sharedImage)
1779 {
1780 	sharedImage->addRef();
1781 
1782 	if(image[0])
1783 	{
1784 		image[0]->release();
1785 	}
1786 
1787 	image[0] = sharedImage;
1788 }
1789 
1790 // Tests for 3D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
isSamplerComplete() const1791 bool Texture3D::isSamplerComplete() const
1792 {
1793 	if(!image[0])
1794 	{
1795 		return false;
1796 	}
1797 
1798 	GLsizei width = image[0]->getWidth();
1799 	GLsizei height = image[0]->getHeight();
1800 	GLsizei depth = image[0]->getDepth();
1801 
1802 	if(width <= 0 || height <= 0 || depth <= 0)
1803 	{
1804 		return false;
1805 	}
1806 
1807 	if(isMipmapFiltered())
1808 	{
1809 		if(!isMipmapComplete())
1810 		{
1811 			return false;
1812 		}
1813 	}
1814 
1815 	return true;
1816 }
1817 
1818 // Tests for 3D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
isMipmapComplete() const1819 bool Texture3D::isMipmapComplete() const
1820 {
1821 	GLsizei width = image[mBaseLevel]->getWidth();
1822 	GLsizei height = image[mBaseLevel]->getHeight();
1823 	GLsizei depth = image[mBaseLevel]->getDepth();
1824 	bool isTexture2DArray = getTarget() == GL_TEXTURE_2D_ARRAY;
1825 
1826 	int q = isTexture2DArray ? std::min(log2(std::max(width, height)), mMaxLevel) :
1827 	        std::min(log2(std::max(std::max(width, height), depth)), mMaxLevel);
1828 
1829 	for(int level = mBaseLevel + 1; level <= q; level++)
1830 	{
1831 		if(!image[level])
1832 		{
1833 			return false;
1834 		}
1835 
1836 		if(image[level]->getFormat() != image[0]->getFormat())
1837 		{
1838 			return false;
1839 		}
1840 
1841 		if(image[level]->getType() != image[0]->getType())
1842 		{
1843 			return false;
1844 		}
1845 
1846 		if(image[level]->getWidth() != std::max(1, width >> level))
1847 		{
1848 			return false;
1849 		}
1850 
1851 		if(image[level]->getHeight() != std::max(1, height >> level))
1852 		{
1853 			return false;
1854 		}
1855 
1856 		int levelDepth = isTexture2DArray ? depth : std::max(1, depth >> level);
1857 		if(image[level]->getDepth() != levelDepth)
1858 		{
1859 			return false;
1860 		}
1861 	}
1862 
1863 	return true;
1864 }
1865 
isCompressed(GLenum target,GLint level) const1866 bool Texture3D::isCompressed(GLenum target, GLint level) const
1867 {
1868 	return IsCompressed(getFormat(target, level), egl::getClientVersion());
1869 }
1870 
isDepth(GLenum target,GLint level) const1871 bool Texture3D::isDepth(GLenum target, GLint level) const
1872 {
1873 	return IsDepthTexture(getFormat(target, level));
1874 }
1875 
generateMipmaps()1876 void Texture3D::generateMipmaps()
1877 {
1878 	if(!image[0])
1879 	{
1880 		return;   // FIXME: error?
1881 	}
1882 
1883 	unsigned int q = log2(std::max(std::max(image[0]->getWidth(), image[0]->getHeight()), image[0]->getDepth()));
1884 
1885 	for(unsigned int i = 1; i <= q; i++)
1886 	{
1887 		if(image[i])
1888 		{
1889 			image[i]->release();
1890 		}
1891 
1892 		image[i] = new egl::Image(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());
1893 
1894 		if(!image[i])
1895 		{
1896 			return error(GL_OUT_OF_MEMORY);
1897 		}
1898 
1899 		getDevice()->stretchCube(image[i - 1], image[i]);
1900 	}
1901 }
1902 
getImage(unsigned int level)1903 egl::Image *Texture3D::getImage(unsigned int level)
1904 {
1905 	return image[level];
1906 }
1907 
getRenderbuffer(GLenum target,GLint level,GLint layer)1908 Renderbuffer *Texture3D::getRenderbuffer(GLenum target, GLint level, GLint layer)
1909 {
1910 	if(target != getTarget())
1911 	{
1912 		return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
1913 	}
1914 
1915 	if(!mColorbufferProxy)
1916 	{
1917 		mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture3D(this, level, layer));
1918 	}
1919 	else
1920 	{
1921 		mColorbufferProxy->setLevel(level);
1922 		mColorbufferProxy->setLayer(layer);
1923 	}
1924 
1925 	return mColorbufferProxy;
1926 }
1927 
getRenderTarget(GLenum target,unsigned int level)1928 egl::Image *Texture3D::getRenderTarget(GLenum target, unsigned int level)
1929 {
1930 	ASSERT(target == getTarget());
1931 	ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1932 
1933 	if(image[level])
1934 	{
1935 		image[level]->addRef();
1936 	}
1937 
1938 	return image[level];
1939 }
1940 
isShared(GLenum target,unsigned int level) const1941 bool Texture3D::isShared(GLenum target, unsigned int level) const
1942 {
1943 	ASSERT(target == getTarget());
1944 	ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1945 
1946 	if(mSurface)   // Bound to an EGLSurface
1947 	{
1948 		return true;
1949 	}
1950 
1951 	if(!image[level])
1952 	{
1953 		return false;
1954 	}
1955 
1956 	return image[level]->isShared();
1957 }
1958 
Texture2DArray(GLuint name)1959 Texture2DArray::Texture2DArray(GLuint name) : Texture3D(name)
1960 {
1961 }
1962 
~Texture2DArray()1963 Texture2DArray::~Texture2DArray()
1964 {
1965 }
1966 
getTarget() const1967 GLenum Texture2DArray::getTarget() const
1968 {
1969 	return GL_TEXTURE_2D_ARRAY;
1970 }
1971 
generateMipmaps()1972 void Texture2DArray::generateMipmaps()
1973 {
1974 	int depth = image[0] ? image[0]->getDepth() : 0;
1975 	if(!depth)
1976 	{
1977 		return;   // FIXME: error?
1978 	}
1979 
1980 	unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight()));
1981 
1982 	for(unsigned int i = 1; i <= q; i++)
1983 	{
1984 		if(image[i])
1985 		{
1986 			image[i]->release();
1987 		}
1988 
1989 		GLsizei w = std::max(image[0]->getWidth() >> i, 1);
1990 		GLsizei h = std::max(image[0]->getHeight() >> i, 1);
1991 		image[i] = new egl::Image(this, w, h, depth, image[0]->getFormat(), image[0]->getType());
1992 
1993 		if(!image[i])
1994 		{
1995 			return error(GL_OUT_OF_MEMORY);
1996 		}
1997 
1998 		GLsizei srcw = image[i - 1]->getWidth();
1999 		GLsizei srch = image[i - 1]->getHeight();
2000 		for(int z = 0; z < depth; ++z)
2001 		{
2002 			sw::SliceRect srcRect(0, 0, srcw, srch, z);
2003 			sw::SliceRect dstRect(0, 0, w, h, z);
2004 			getDevice()->stretchRect(image[i - 1], &srcRect, image[i], &dstRect, true);
2005 		}
2006 	}
2007 }
2008 
TextureExternal(GLuint name)2009 TextureExternal::TextureExternal(GLuint name) : Texture2D(name)
2010 {
2011 	mMinFilter = GL_LINEAR;
2012 	mMagFilter = GL_LINEAR;
2013 	mWrapS = GL_CLAMP_TO_EDGE;
2014 	mWrapT = GL_CLAMP_TO_EDGE;
2015 	mWrapR = GL_CLAMP_TO_EDGE;
2016 }
2017 
~TextureExternal()2018 TextureExternal::~TextureExternal()
2019 {
2020 }
2021 
getTarget() const2022 GLenum TextureExternal::getTarget() const
2023 {
2024 	return GL_TEXTURE_EXTERNAL_OES;
2025 }
2026 
2027 }
2028 
createBackBuffer(int width,int height,const egl::Config * config)2029 egl::Image *createBackBuffer(int width, int height, const egl::Config *config)
2030 {
2031 	if(config)
2032 	{
2033 		return new egl::Image(width, height, config->mRenderTargetFormat, config->mSamples, false);
2034 	}
2035 
2036 	return nullptr;
2037 }
2038 
createDepthStencil(unsigned int width,unsigned int height,sw::Format format,int multiSampleDepth,bool discard)2039 egl::Image *createDepthStencil(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)
2040 {
2041 	if(width == 0 || height == 0 || height > sw::OUTLINE_RESOLUTION)
2042 	{
2043 		ERR("Invalid parameters: %dx%d", width, height);
2044 		return nullptr;
2045 	}
2046 
2047 	bool lockable = true;
2048 
2049 	switch(format)
2050 	{
2051 //	case sw::FORMAT_D15S1:
2052 	case sw::FORMAT_D24S8:
2053 	case sw::FORMAT_D24X8:
2054 //	case sw::FORMAT_D24X4S4:
2055 	case sw::FORMAT_D24FS8:
2056 	case sw::FORMAT_D32:
2057 	case sw::FORMAT_D16:
2058 		lockable = false;
2059 		break;
2060 //	case sw::FORMAT_S8_LOCKABLE:
2061 //	case sw::FORMAT_D16_LOCKABLE:
2062 	case sw::FORMAT_D32F_LOCKABLE:
2063 //	case sw::FORMAT_D32_LOCKABLE:
2064 	case sw::FORMAT_DF24S8:
2065 	case sw::FORMAT_DF16S8:
2066 		lockable = true;
2067 		break;
2068 	default:
2069 		UNREACHABLE(format);
2070 	}
2071 
2072 	egl::Image *surface = new egl::Image(width, height, format, multiSampleDepth, lockable);
2073 
2074 	if(!surface)
2075 	{
2076 		ERR("Out of memory");
2077 		return nullptr;
2078 	}
2079 
2080 	return surface;
2081 }
2082