Home | History | Annotate | Download | only in libGLES_CM
      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 and TextureCubeMap. Implements GL texture objects and related
     17 // functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
     18 
     19 #include "Texture.h"
     20 
     21 #include "main.h"
     22 #include "mathutil.h"
     23 #include "Framebuffer.h"
     24 #include "Device.hpp"
     25 #include "libEGL/Display.h"
     26 #include "common/Surface.hpp"
     27 #include "common/debug.h"
     28 
     29 #include <algorithm>
     30 
     31 namespace es1
     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 	mMaxAnisotropy = 1.0f;
     41 	generateMipmap = GL_FALSE;
     42 	cropRectU = 0;
     43 	cropRectV = 0;
     44 	cropRectW = 0;
     45 	cropRectH = 0;
     46 
     47 	resource = new sw::Resource(0);
     48 }
     49 
     50 Texture::~Texture()
     51 {
     52 	resource->destruct();
     53 }
     54 
     55 sw::Resource *Texture::getResource() const
     56 {
     57 	return resource;
     58 }
     59 
     60 // Returns true on successful filter state update (valid enum parameter)
     61 bool Texture::setMinFilter(GLenum filter)
     62 {
     63 	switch(filter)
     64 	{
     65 	case GL_NEAREST_MIPMAP_NEAREST:
     66 	case GL_LINEAR_MIPMAP_NEAREST:
     67 	case GL_NEAREST_MIPMAP_LINEAR:
     68 	case GL_LINEAR_MIPMAP_LINEAR:
     69 		if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
     70 		{
     71 			return false;
     72 		}
     73 		// Fall through
     74 	case GL_NEAREST:
     75 	case GL_LINEAR:
     76 		mMinFilter = filter;
     77 		return true;
     78 	default:
     79 		return false;
     80 	}
     81 }
     82 
     83 // Returns true on successful filter state update (valid enum parameter)
     84 bool Texture::setMagFilter(GLenum filter)
     85 {
     86 	switch(filter)
     87 	{
     88 	case GL_NEAREST:
     89 	case GL_LINEAR:
     90 		mMagFilter = filter;
     91 		return true;
     92 	default:
     93 		return false;
     94 	}
     95 }
     96 
     97 // Returns true on successful wrap state update (valid enum parameter)
     98 bool Texture::setWrapS(GLenum wrap)
     99 {
    100 	switch(wrap)
    101 	{
    102 	case GL_REPEAT:
    103 	case GL_MIRRORED_REPEAT_OES:
    104 		if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
    105 		{
    106 			return false;
    107 		}
    108 		// Fall through
    109 	case GL_CLAMP_TO_EDGE:
    110 		mWrapS = wrap;
    111 		return true;
    112 	default:
    113 		return false;
    114 	}
    115 }
    116 
    117 // Returns true on successful wrap state update (valid enum parameter)
    118 bool Texture::setWrapT(GLenum wrap)
    119 {
    120 	switch(wrap)
    121 	{
    122 	case GL_REPEAT:
    123 	case GL_MIRRORED_REPEAT_OES:
    124 		if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
    125 		{
    126 			return false;
    127 		}
    128 		// Fall through
    129 	case GL_CLAMP_TO_EDGE:
    130 		 mWrapT = wrap;
    131 		 return true;
    132 	default:
    133 		return false;
    134 	}
    135 }
    136 
    137 // Returns true on successful max anisotropy update (valid anisotropy value)
    138 bool Texture::setMaxAnisotropy(float textureMaxAnisotropy)
    139 {
    140 	textureMaxAnisotropy = std::min(textureMaxAnisotropy, MAX_TEXTURE_MAX_ANISOTROPY);
    141 
    142 	if(textureMaxAnisotropy < 1.0f)
    143 	{
    144 		return false;
    145 	}
    146 
    147 	if(mMaxAnisotropy != textureMaxAnisotropy)
    148 	{
    149 		mMaxAnisotropy = textureMaxAnisotropy;
    150 	}
    151 
    152 	return true;
    153 }
    154 
    155 void Texture::setGenerateMipmap(GLboolean enable)
    156 {
    157 	generateMipmap = enable;
    158 }
    159 
    160 void Texture::setCropRect(GLint u, GLint v, GLint w, GLint h)
    161 {
    162 	cropRectU = u;
    163 	cropRectV = v;
    164 	cropRectW = w;
    165 	cropRectH = h;
    166 }
    167 
    168 GLenum Texture::getMinFilter() const
    169 {
    170 	return mMinFilter;
    171 }
    172 
    173 GLenum Texture::getMagFilter() const
    174 {
    175 	return mMagFilter;
    176 }
    177 
    178 GLenum Texture::getWrapS() const
    179 {
    180 	return mWrapS;
    181 }
    182 
    183 GLenum Texture::getWrapT() const
    184 {
    185 	return mWrapT;
    186 }
    187 
    188 GLfloat Texture::getMaxAnisotropy() const
    189 {
    190 	return mMaxAnisotropy;
    191 }
    192 
    193 GLboolean Texture::getGenerateMipmap() const
    194 {
    195 	return generateMipmap;
    196 }
    197 
    198 GLint Texture::getCropRectU() const
    199 {
    200 	return cropRectU;
    201 }
    202 
    203 GLint Texture::getCropRectV() const
    204 {
    205 	return cropRectV;
    206 }
    207 
    208 GLint Texture::getCropRectW() const
    209 {
    210 	return cropRectW;
    211 }
    212 
    213 GLint Texture::getCropRectH() const
    214 {
    215 	return cropRectH;
    216 }
    217 
    218 egl::Image *Texture::createSharedImage(GLenum target, unsigned int level)
    219 {
    220 	egl::Image *image = getRenderTarget(target, level);   // Increments reference count
    221 
    222 	if(image)
    223 	{
    224 		image->markShared();
    225 	}
    226 
    227 	return image;
    228 }
    229 
    230 void Texture::setImage(egl::Context *context, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image)
    231 {
    232 	if(pixels && image)
    233 	{
    234 		egl::Image::UnpackInfo unpackInfo;
    235 		unpackInfo.alignment = unpackAlignment;
    236 		image->loadImageData(context, 0, 0, 0, image->getWidth(), image->getHeight(), 1, format, type, unpackInfo, pixels);
    237 	}
    238 }
    239 
    240 void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, egl::Image *image)
    241 {
    242 	if(pixels && image)
    243 	{
    244 		image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), 1, imageSize, pixels);
    245 	}
    246 }
    247 
    248 void Texture::subImage(egl::Context *context, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image)
    249 {
    250 	if(!image)
    251 	{
    252 		return error(GL_INVALID_OPERATION);
    253 	}
    254 
    255 	if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
    256 	{
    257 		return error(GL_INVALID_VALUE);
    258 	}
    259 
    260 	if(IsCompressed(image->getFormat()))
    261 	{
    262 		return error(GL_INVALID_OPERATION);
    263 	}
    264 
    265 	if(format != image->getFormat())
    266 	{
    267 		return error(GL_INVALID_OPERATION);
    268 	}
    269 
    270 	if(pixels)
    271 	{
    272 		egl::Image::UnpackInfo unpackInfo;
    273 		unpackInfo.alignment = unpackAlignment;
    274 		image->loadImageData(context, xoffset, yoffset, 0, width, height, 1, format, type, unpackInfo, pixels);
    275 	}
    276 }
    277 
    278 void Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, egl::Image *image)
    279 {
    280 	if(!image)
    281 	{
    282 		return error(GL_INVALID_OPERATION);
    283 	}
    284 
    285 	if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
    286 	{
    287 		return error(GL_INVALID_VALUE);
    288 	}
    289 
    290 	if(format != image->getFormat())
    291 	{
    292 		return error(GL_INVALID_OPERATION);
    293 	}
    294 
    295 	if(pixels)
    296 	{
    297 		image->loadCompressedData(xoffset, yoffset, 0, width, height, 1, imageSize, pixels);
    298 	}
    299 }
    300 
    301 bool Texture::copy(egl::Image *source, const sw::Rect &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, egl::Image *dest)
    302 {
    303 	Device *device = getDevice();
    304 
    305 	sw::SliceRect destRect(xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0), 0);
    306 	sw::SliceRect sourceSliceRect(sourceRect);
    307 	bool success = device->stretchRect(source, &sourceSliceRect, dest, &destRect, false);
    308 
    309 	if(!success)
    310 	{
    311 		return error(GL_OUT_OF_MEMORY, false);
    312 	}
    313 
    314 	return true;
    315 }
    316 
    317 bool Texture::isMipmapFiltered() const
    318 {
    319 	switch(mMinFilter)
    320 	{
    321 	case GL_NEAREST:
    322 	case GL_LINEAR:
    323 		return false;
    324 	case GL_NEAREST_MIPMAP_NEAREST:
    325 	case GL_LINEAR_MIPMAP_NEAREST:
    326 	case GL_NEAREST_MIPMAP_LINEAR:
    327 	case GL_LINEAR_MIPMAP_LINEAR:
    328 		return true;
    329 	default: UNREACHABLE(mMinFilter);
    330 	}
    331 
    332 	return false;
    333 }
    334 
    335 Texture2D::Texture2D(GLuint name) : Texture(name)
    336 {
    337 	for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
    338 	{
    339 		image[i] = nullptr;
    340 	}
    341 
    342 	mSurface = nullptr;
    343 
    344 	mColorbufferProxy = nullptr;
    345 	mProxyRefs = 0;
    346 }
    347 
    348 Texture2D::~Texture2D()
    349 {
    350 	for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
    351 	{
    352 		if(image[i])
    353 		{
    354 			image[i]->unbind(this);
    355 			image[i] = nullptr;
    356 		}
    357 	}
    358 
    359 	if(mSurface)
    360 	{
    361 		mSurface->setBoundTexture(nullptr);
    362 		mSurface = nullptr;
    363 	}
    364 
    365 	mColorbufferProxy = nullptr;
    366 }
    367 
    368 // We need to maintain a count of references to renderbuffers acting as
    369 // proxies for this texture, so that we do not attempt to use a pointer
    370 // to a renderbuffer proxy which has been deleted.
    371 void Texture2D::addProxyRef(const Renderbuffer *proxy)
    372 {
    373 	mProxyRefs++;
    374 }
    375 
    376 void Texture2D::releaseProxy(const Renderbuffer *proxy)
    377 {
    378 	if(mProxyRefs > 0)
    379 	{
    380 		mProxyRefs--;
    381 	}
    382 
    383 	if(mProxyRefs == 0)
    384 	{
    385 		mColorbufferProxy = nullptr;
    386 	}
    387 }
    388 
    389 void Texture2D::sweep()
    390 {
    391 	int imageCount = 0;
    392 
    393 	for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
    394 	{
    395 		if(image[i] && image[i]->isChildOf(this))
    396 		{
    397 			if(!image[i]->hasSingleReference())
    398 			{
    399 				return;
    400 			}
    401 
    402 			imageCount++;
    403 		}
    404 	}
    405 
    406 	if(imageCount == referenceCount)
    407 	{
    408 		destroy();
    409 	}
    410 }
    411 
    412 GLenum Texture2D::getTarget() const
    413 {
    414 	return GL_TEXTURE_2D;
    415 }
    416 
    417 GLsizei Texture2D::getWidth(GLenum target, GLint level) const
    418 {
    419 	ASSERT(target == GL_TEXTURE_2D);
    420 	return image[level] ? image[level]->getWidth() : 0;
    421 }
    422 
    423 GLsizei Texture2D::getHeight(GLenum target, GLint level) const
    424 {
    425 	ASSERT(target == GL_TEXTURE_2D);
    426 	return image[level] ? image[level]->getHeight() : 0;
    427 }
    428 
    429 GLenum Texture2D::getFormat(GLenum target, GLint level) const
    430 {
    431 	ASSERT(target == GL_TEXTURE_2D);
    432 	return image[level] ? image[level]->getFormat() : GL_NONE;
    433 }
    434 
    435 GLenum Texture2D::getType(GLenum target, GLint level) const
    436 {
    437 	ASSERT(target == GL_TEXTURE_2D);
    438 	return image[level] ? image[level]->getType() : GL_NONE;
    439 }
    440 
    441 sw::Format Texture2D::getInternalFormat(GLenum target, GLint level) const
    442 {
    443 	ASSERT(target == GL_TEXTURE_2D);
    444 	return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
    445 }
    446 
    447 int Texture2D::getLevelCount() const
    448 {
    449 	ASSERT(isSamplerComplete());
    450 	int levels = 0;
    451 
    452 	while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[levels])
    453 	{
    454 		levels++;
    455 	}
    456 
    457 	return levels;
    458 }
    459 
    460 void Texture2D::setImage(egl::Context *context, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
    461 {
    462 	if(image[level])
    463 	{
    464 		image[level]->release();
    465 	}
    466 
    467 	image[level] = egl::Image::create(this, width, height, format, type);
    468 
    469 	if(!image[level])
    470 	{
    471 		return error(GL_OUT_OF_MEMORY);
    472 	}
    473 
    474 	Texture::setImage(context, format, type, unpackAlignment, pixels, image[level]);
    475 }
    476 
    477 void Texture2D::bindTexImage(gl::Surface *surface)
    478 {
    479 	switch(surface->getInternalFormat())
    480 	{
    481 	case sw::FORMAT_A8R8G8B8:
    482 	case sw::FORMAT_A8B8G8R8:
    483 	case sw::FORMAT_X8B8G8R8:
    484 	case sw::FORMAT_X8R8G8B8:
    485 		break;
    486 	default:
    487 		UNIMPLEMENTED();
    488 		return;
    489 	}
    490 
    491 	for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
    492 	{
    493 		if(image[level])
    494 		{
    495 			image[level]->release();
    496 			image[level] = nullptr;
    497 		}
    498 	}
    499 
    500 	image[0] = surface->getRenderTarget();
    501 
    502 	mSurface = surface;
    503 	mSurface->setBoundTexture(this);
    504 }
    505 
    506 void Texture2D::releaseTexImage()
    507 {
    508 	for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
    509 	{
    510 		if(image[level])
    511 		{
    512 			image[level]->release();
    513 			image[level] = nullptr;
    514 		}
    515 	}
    516 }
    517 
    518 void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
    519 {
    520 	if(image[level])
    521 	{
    522 		image[level]->release();
    523 	}
    524 
    525 	image[level] = egl::Image::create(this, width, height, format, GL_UNSIGNED_BYTE);
    526 
    527 	if(!image[level])
    528 	{
    529 		return error(GL_OUT_OF_MEMORY);
    530 	}
    531 
    532 	Texture::setCompressedImage(imageSize, pixels, image[level]);
    533 }
    534 
    535 void Texture2D::subImage(egl::Context *context, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
    536 {
    537 	Texture::subImage(context, xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, image[level]);
    538 }
    539 
    540 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
    541 {
    542 	Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, image[level]);
    543 }
    544 
    545 void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
    546 {
    547 	egl::Image *renderTarget = source->getRenderTarget();
    548 
    549 	if(!renderTarget)
    550 	{
    551 		ERR("Failed to retrieve the render target.");
    552 		return error(GL_OUT_OF_MEMORY);
    553 	}
    554 
    555 	if(image[level])
    556 	{
    557 		image[level]->release();
    558 	}
    559 
    560 	image[level] = egl::Image::create(this, width, height, format, GL_UNSIGNED_BYTE);
    561 
    562 	if(!image[level])
    563 	{
    564 		return error(GL_OUT_OF_MEMORY);
    565 	}
    566 
    567 	if(width != 0 && height != 0)
    568 	{
    569 		sw::Rect sourceRect = {x, y, x + width, y + height};
    570 		sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());
    571 
    572 		copy(renderTarget, sourceRect, format, 0, 0, image[level]);
    573 	}
    574 
    575 	renderTarget->release();
    576 }
    577 
    578 void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
    579 {
    580 	if(!image[level])
    581 	{
    582 		return error(GL_INVALID_OPERATION);
    583 	}
    584 
    585 	if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight())
    586 	{
    587 		return error(GL_INVALID_VALUE);
    588 	}
    589 
    590 	egl::Image *renderTarget = source->getRenderTarget();
    591 
    592 	if(!renderTarget)
    593 	{
    594 		ERR("Failed to retrieve the render target.");
    595 		return error(GL_OUT_OF_MEMORY);
    596 	}
    597 
    598 	sw::Rect sourceRect = {x, y, x + width, y + height};
    599 	sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());
    600 
    601 	copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, image[level]);
    602 
    603 	renderTarget->release();
    604 }
    605 
    606 void Texture2D::setSharedImage(egl::Image *sharedImage)
    607 {
    608 	sharedImage->addRef();
    609 
    610 	if(image[0])
    611 	{
    612 		image[0]->release();
    613 	}
    614 
    615 	image[0] = sharedImage;
    616 }
    617 
    618 // Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
    619 bool Texture2D::isSamplerComplete() const
    620 {
    621 	if(!image[0])
    622 	{
    623 		return false;
    624 	}
    625 
    626 	GLsizei width = image[0]->getWidth();
    627 	GLsizei height = image[0]->getHeight();
    628 
    629 	if(width <= 0 || height <= 0)
    630 	{
    631 		return false;
    632 	}
    633 
    634 	if(isMipmapFiltered())
    635 	{
    636 		if(!generateMipmap && !isMipmapComplete())
    637 		{
    638 			return false;
    639 		}
    640 	}
    641 
    642 	return true;
    643 }
    644 
    645 // Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
    646 bool Texture2D::isMipmapComplete() const
    647 {
    648 	GLsizei width = image[0]->getWidth();
    649 	GLsizei height = image[0]->getHeight();
    650 
    651 	int q = log2(std::max(width, height));
    652 
    653 	for(int level = 1; level <= q; level++)
    654 	{
    655 		if(!image[level])
    656 		{
    657 			return false;
    658 		}
    659 
    660 		if(image[level]->getFormat() != image[0]->getFormat())
    661 		{
    662 			return false;
    663 		}
    664 
    665 		if(image[level]->getType() != image[0]->getType())
    666 		{
    667 			return false;
    668 		}
    669 
    670 		if(image[level]->getWidth() != std::max(1, width >> level))
    671 		{
    672 			return false;
    673 		}
    674 
    675 		if(image[level]->getHeight() != std::max(1, height >> level))
    676 		{
    677 			return false;
    678 		}
    679 	}
    680 
    681 	return true;
    682 }
    683 
    684 bool Texture2D::isCompressed(GLenum target, GLint level) const
    685 {
    686 	return IsCompressed(getFormat(target, level));
    687 }
    688 
    689 bool Texture2D::isDepth(GLenum target, GLint level) const
    690 {
    691 	return IsDepthTexture(getFormat(target, level));
    692 }
    693 
    694 void Texture2D::generateMipmaps()
    695 {
    696 	if(!image[0])
    697 	{
    698 		return;   // FIXME: error?
    699 	}
    700 
    701 	unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight()));
    702 
    703 	for(unsigned int i = 1; i <= q; i++)
    704 	{
    705 		if(image[i])
    706 		{
    707 			image[i]->release();
    708 		}
    709 
    710 		image[i] = egl::Image::create(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), image[0]->getFormat(), image[0]->getType());
    711 
    712 		if(!image[i])
    713 		{
    714 			return error(GL_OUT_OF_MEMORY);
    715 		}
    716 
    717 		getDevice()->stretchRect(image[i - 1], 0, image[i], 0, true);
    718 	}
    719 }
    720 
    721 void Texture2D::autoGenerateMipmaps()
    722 {
    723 	if(generateMipmap && image[0]->hasDirtyMipmaps())
    724 	{
    725 		generateMipmaps();
    726 		image[0]->cleanMipmaps();
    727 	}
    728 }
    729 
    730 egl::Image *Texture2D::getImage(unsigned int level)
    731 {
    732 	return image[level];
    733 }
    734 
    735 Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
    736 {
    737 	if(target != GL_TEXTURE_2D)
    738 	{
    739 		return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
    740 	}
    741 
    742 	if(!mColorbufferProxy)
    743 	{
    744 		mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture2D(this));
    745 	}
    746 
    747 	return mColorbufferProxy;
    748 }
    749 
    750 egl::Image *Texture2D::getRenderTarget(GLenum target, unsigned int level)
    751 {
    752 	ASSERT(target == GL_TEXTURE_2D);
    753 	ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
    754 
    755 	if(image[level])
    756 	{
    757 		image[level]->addRef();
    758 	}
    759 
    760 	return image[level];
    761 }
    762 
    763 bool Texture2D::isShared(GLenum target, unsigned int level) const
    764 {
    765 	ASSERT(target == GL_TEXTURE_2D);
    766 	ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
    767 
    768 	if(mSurface)   // Bound to an EGLSurface
    769 	{
    770 		return true;
    771 	}
    772 
    773 	if(!image[level])
    774 	{
    775 		return false;
    776 	}
    777 
    778 	return image[level]->isShared();
    779 }
    780 
    781 TextureExternal::TextureExternal(GLuint name) : Texture2D(name)
    782 {
    783 	mMinFilter = GL_LINEAR;
    784 	mMagFilter = GL_LINEAR;
    785 	mWrapS = GL_CLAMP_TO_EDGE;
    786 	mWrapT = GL_CLAMP_TO_EDGE;
    787 }
    788 
    789 TextureExternal::~TextureExternal()
    790 {
    791 }
    792 
    793 GLenum TextureExternal::getTarget() const
    794 {
    795 	return GL_TEXTURE_EXTERNAL_OES;
    796 }
    797 
    798 }
    799 
    800 egl::Image *createBackBuffer(int width, int height, sw::Format format, int multiSampleDepth)
    801 {
    802 	if(width > es1::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE || height > es1::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE)
    803 	{
    804 		ERR("Invalid parameters: %dx%d", width, height);
    805 		return nullptr;
    806 	}
    807 
    808 	return egl::Image::create(width, height, format, multiSampleDepth, false);
    809 }
    810 
    811 egl::Image *createDepthStencil(int width, int height, sw::Format format, int multiSampleDepth)
    812 {
    813 	if(width > es1::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE || height > es1::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE)
    814 	{
    815 		ERR("Invalid parameters: %dx%d", width, height);
    816 		return nullptr;
    817 	}
    818 
    819 	bool lockable = true;
    820 
    821 	switch(format)
    822 	{
    823 //	case sw::FORMAT_D15S1:
    824 	case sw::FORMAT_D24S8:
    825 	case sw::FORMAT_D24X8:
    826 //	case sw::FORMAT_D24X4S4:
    827 	case sw::FORMAT_D24FS8:
    828 	case sw::FORMAT_D32:
    829 	case sw::FORMAT_D16:
    830 		lockable = false;
    831 		break;
    832 //	case sw::FORMAT_S8_LOCKABLE:
    833 //	case sw::FORMAT_D16_LOCKABLE:
    834 	case sw::FORMAT_D32F_LOCKABLE:
    835 //	case sw::FORMAT_D32_LOCKABLE:
    836 	case sw::FORMAT_DF24S8:
    837 	case sw::FORMAT_DF16S8:
    838 		lockable = true;
    839 		break;
    840 	default:
    841 		UNREACHABLE(format);
    842 	}
    843 
    844 	egl::Image *surface = egl::Image::create(width, height, format, multiSampleDepth, lockable);
    845 
    846 	if(!surface)
    847 	{
    848 		ERR("Out of memory");
    849 		return nullptr;
    850 	}
    851 
    852 	return surface;
    853 }
    854