Home | History | Annotate | Download | only in libGLESv2
      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 
     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 
     58 Texture::~Texture()
     59 {
     60 	resource->destruct();
     61 }
     62 
     63 sw::Resource *Texture::getResource() const
     64 {
     65 	return resource;
     66 }
     67 
     68 // Returns true on successful filter state update (valid enum parameter)
     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)
     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)
    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)
    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)
    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)
    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 
    183 bool Texture::setBaseLevel(GLint baseLevel)
    184 {
    185 	mBaseLevel = baseLevel;
    186 	return true;
    187 }
    188 
    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 
    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 
    221 void Texture::makeImmutable(GLsizei levels)
    222 {
    223 	mImmutableFormat = GL_TRUE;
    224 	mImmutableLevels = levels;
    225 }
    226 
    227 bool Texture::setMaxLevel(GLint maxLevel)
    228 {
    229 	mMaxLevel = maxLevel;
    230 	return true;
    231 }
    232 
    233 bool Texture::setMaxLOD(GLfloat maxLOD)
    234 {
    235 	mMaxLOD = maxLOD;
    236 	return true;
    237 }
    238 
    239 bool Texture::setMinLOD(GLfloat minLOD)
    240 {
    241 	mMinLOD = minLOD;
    242 	return true;
    243 }
    244 
    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 
    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 
    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 
    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 
    313 GLenum Texture::getMinFilter() const
    314 {
    315 	return mMinFilter;
    316 }
    317 
    318 GLenum Texture::getMagFilter() const
    319 {
    320 	return mMagFilter;
    321 }
    322 
    323 GLenum Texture::getWrapS() const
    324 {
    325 	return mWrapS;
    326 }
    327 
    328 GLenum Texture::getWrapT() const
    329 {
    330 	return mWrapT;
    331 }
    332 
    333 GLenum Texture::getWrapR() const
    334 {
    335 	return mWrapR;
    336 }
    337 
    338 GLfloat Texture::getMaxAnisotropy() const
    339 {
    340 	return mMaxAnisotropy;
    341 }
    342 
    343 GLint Texture::getBaseLevel() const
    344 {
    345 	return mBaseLevel;
    346 }
    347 GLenum Texture::getCompareFunc() const
    348 {
    349 	return mCompareFunc;
    350 }
    351 GLenum Texture::getCompareMode() const
    352 {
    353 	return mCompareMode;
    354 }
    355 GLboolean Texture::getImmutableFormat() const
    356 {
    357 	return mImmutableFormat;
    358 }
    359 GLsizei Texture::getImmutableLevels() const
    360 {
    361 	return mImmutableLevels;
    362 }
    363 GLint Texture::getMaxLevel() const
    364 {
    365 	return mMaxLevel;
    366 }
    367 GLfloat Texture::getMaxLOD() const
    368 {
    369 	return mMaxLOD;
    370 }
    371 GLfloat Texture::getMinLOD() const
    372 {
    373 	return mMinLOD;
    374 }
    375 GLenum Texture::getSwizzleR() const
    376 {
    377 	return mSwizzleR;
    378 }
    379 GLenum Texture::getSwizzleG() const
    380 {
    381 	return mSwizzleG;
    382 }
    383 GLenum Texture::getSwizzleB() const
    384 {
    385 	return mSwizzleB;
    386 }
    387 GLenum Texture::getSwizzleA() const
    388 {
    389 	return mSwizzleA;
    390 }
    391 
    392 GLsizei Texture::getDepth(GLenum target, GLint level) const
    393 {
    394 	return 1;
    395 }
    396 
    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 
    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 
    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 
    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 
    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 
    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 
    493 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 
    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 
    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.
    551 void Texture2D::addProxyRef(const Renderbuffer *proxy)
    552 {
    553 	mProxyRefs++;
    554 }
    555 
    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 
    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 
    592 GLenum Texture2D::getTarget() const
    593 {
    594 	return GL_TEXTURE_2D;
    595 }
    596 
    597 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 
    603 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 
    609 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 
    615 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 
    621 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 
    627 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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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.
    831 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.
    858 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 
    896 bool Texture2D::isCompressed(GLenum target, GLint level) const
    897 {
    898 	return IsCompressed(getFormat(target, level), egl::getClientVersion());
    899 }
    900 
    901 bool Texture2D::isDepth(GLenum target, GLint level) const
    902 {
    903 	return IsDepthTexture(getFormat(target, level));
    904 }
    905 
    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 
    933 egl::Image *Texture2D::getImage(unsigned int level)
    934 {
    935 	return image[level];
    936 }
    937 
    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 
    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 
    970 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 
    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 
   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.
   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 
   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 
   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 
   1090 GLenum TextureCubeMap::getTarget() const
   1091 {
   1092 	return GL_TEXTURE_CUBE_MAP;
   1093 }
   1094 
   1095 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 
   1101 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 
   1107 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 
   1113 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 
   1119 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 
   1125 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 
   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 
   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 
   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.
   1169 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.
   1205 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 
   1226 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 
   1265 bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
   1266 {
   1267 	return IsCompressed(getFormat(target, level), egl::getClientVersion());
   1268 }
   1269 
   1270 bool TextureCubeMap::isDepth(GLenum target, GLint level) const
   1271 {
   1272 	return IsDepthTexture(getFormat(target, level));
   1273 }
   1274 
   1275 void TextureCubeMap::releaseTexImage()
   1276 {
   1277 	UNREACHABLE(0);   // Cube maps cannot have an EGL surface bound as an image
   1278 }
   1279 
   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 
   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 
   1343 egl::Image *TextureCubeMap::getImage(int face, unsigned int level)
   1344 {
   1345 	return image[face][level];
   1346 }
   1347 
   1348 egl::Image *TextureCubeMap::getImage(GLenum face, unsigned int level)
   1349 {
   1350 	return image[CubeFaceIndex(face)][level];
   1351 }
   1352 
   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 
   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 
   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 
   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 
   1459 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 
   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 
   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.
   1514 void Texture3D::addProxyRef(const Renderbuffer *proxy)
   1515 {
   1516 	mProxyRefs++;
   1517 }
   1518 
   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 
   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 
   1555 GLenum Texture3D::getTarget() const
   1556 {
   1557 	return GL_TEXTURE_3D_OES;
   1558 }
   1559 
   1560 GLsizei Texture3D::getWidth(GLenum target, GLint level) const
   1561 {
   1562 	ASSERT(target == getTarget());
   1563 	return image[level] ? image[level]->getWidth() : 0;
   1564 }
   1565 
   1566 GLsizei Texture3D::getHeight(GLenum target, GLint level) const
   1567 {
   1568 	ASSERT(target == getTarget());
   1569 	return image[level] ? image[level]->getHeight() : 0;
   1570 }
   1571 
   1572 GLsizei Texture3D::getDepth(GLenum target, GLint level) const
   1573 {
   1574 	ASSERT(target == getTarget());
   1575 	return image[level] ? image[level]->getDepth() : 0;
   1576 }
   1577 
   1578 GLenum Texture3D::getFormat(GLenum target, GLint level) const
   1579 {
   1580 	ASSERT(target == getTarget());
   1581 	return image[level] ? image[level]->getFormat() : GL_NONE;
   1582 }
   1583 
   1584 GLenum Texture3D::getType(GLenum target, GLint level) const
   1585 {
   1586 	ASSERT(target == getTarget());
   1587 	return image[level] ? image[level]->getType() : GL_NONE;
   1588 }
   1589 
   1590 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 
   1596 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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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.
   1791 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.
   1819 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 
   1866 bool Texture3D::isCompressed(GLenum target, GLint level) const
   1867 {
   1868 	return IsCompressed(getFormat(target, level), egl::getClientVersion());
   1869 }
   1870 
   1871 bool Texture3D::isDepth(GLenum target, GLint level) const
   1872 {
   1873 	return IsDepthTexture(getFormat(target, level));
   1874 }
   1875 
   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 
   1903 egl::Image *Texture3D::getImage(unsigned int level)
   1904 {
   1905 	return image[level];
   1906 }
   1907 
   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 
   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 
   1941 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 
   1959 Texture2DArray::Texture2DArray(GLuint name) : Texture3D(name)
   1960 {
   1961 }
   1962 
   1963 Texture2DArray::~Texture2DArray()
   1964 {
   1965 }
   1966 
   1967 GLenum Texture2DArray::getTarget() const
   1968 {
   1969 	return GL_TEXTURE_2D_ARRAY;
   1970 }
   1971 
   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 
   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 
   2018 TextureExternal::~TextureExternal()
   2019 {
   2020 }
   2021 
   2022 GLenum TextureExternal::getTarget() const
   2023 {
   2024 	return GL_TEXTURE_EXTERNAL_OES;
   2025 }
   2026 
   2027 }
   2028 
   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 
   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