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 
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 	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 
~Texture()50 Texture::~Texture()
51 {
52 	resource->destruct();
53 }
54 
getResource() const55 sw::Resource *Texture::getResource() const
56 {
57 	return resource;
58 }
59 
60 // Returns true on successful filter state update (valid enum parameter)
setMinFilter(GLenum filter)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)
setMagFilter(GLenum filter)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)
setWrapS(GLenum wrap)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)
setWrapT(GLenum wrap)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)
setMaxAnisotropy(float textureMaxAnisotropy)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 
setGenerateMipmap(GLboolean enable)155 void Texture::setGenerateMipmap(GLboolean enable)
156 {
157 	generateMipmap = enable;
158 }
159 
setCropRect(GLint u,GLint v,GLint w,GLint h)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 
getMinFilter() const168 GLenum Texture::getMinFilter() const
169 {
170 	return mMinFilter;
171 }
172 
getMagFilter() const173 GLenum Texture::getMagFilter() const
174 {
175 	return mMagFilter;
176 }
177 
getWrapS() const178 GLenum Texture::getWrapS() const
179 {
180 	return mWrapS;
181 }
182 
getWrapT() const183 GLenum Texture::getWrapT() const
184 {
185 	return mWrapT;
186 }
187 
getMaxAnisotropy() const188 GLfloat Texture::getMaxAnisotropy() const
189 {
190 	return mMaxAnisotropy;
191 }
192 
getGenerateMipmap() const193 GLboolean Texture::getGenerateMipmap() const
194 {
195 	return generateMipmap;
196 }
197 
getCropRectU() const198 GLint Texture::getCropRectU() const
199 {
200 	return cropRectU;
201 }
202 
getCropRectV() const203 GLint Texture::getCropRectV() const
204 {
205 	return cropRectV;
206 }
207 
getCropRectW() const208 GLint Texture::getCropRectW() const
209 {
210 	return cropRectW;
211 }
212 
getCropRectH() const213 GLint Texture::getCropRectH() const
214 {
215 	return cropRectH;
216 }
217 
createSharedImage(GLenum target,unsigned int level)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 
setImage(GLenum format,GLenum type,GLint unpackAlignment,const void * pixels,egl::Image * image)230 void Texture::setImage(GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image)
231 {
232 	if(pixels && image)
233 	{
234 		gl::PixelStorageModes unpackParameters;
235 		unpackParameters.alignment = unpackAlignment;
236 		image->loadImageData(0, 0, 0, image->getWidth(), image->getHeight(), 1, format, type, unpackParameters, pixels);
237 	}
238 }
239 
setCompressedImage(GLsizei imageSize,const void * pixels,egl::Image * image)240 void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, egl::Image *image)
241 {
242 	if(pixels && image && (imageSize > 0)) // imageSize's correlation to width and height is already validated with gl::ComputeCompressedSize() at the API level
243 	{
244 		image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), 1, imageSize, pixels);
245 	}
246 }
247 
subImage(GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,GLint unpackAlignment,const void * pixels,egl::Image * image)248 void Texture::subImage(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(pixels)
256 	{
257 		gl::PixelStorageModes unpackParameters;
258 		unpackParameters.alignment = unpackAlignment;
259 		image->loadImageData(xoffset, yoffset, 0, width, height, 1, format, type, unpackParameters, pixels);
260 	}
261 }
262 
subImageCompressed(GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLsizei imageSize,const void * pixels,egl::Image * image)263 void Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, egl::Image *image)
264 {
265 	if(!image)
266 	{
267 		return error(GL_INVALID_OPERATION);
268 	}
269 
270 	if(pixels && (imageSize > 0)) // imageSize's correlation to width and height is already validated with gl::ComputeCompressedSize() at the API level
271 	{
272 		image->loadCompressedData(xoffset, yoffset, 0, width, height, 1, imageSize, pixels);
273 	}
274 }
275 
copy(egl::Image * source,const sw::Rect & sourceRect,GLenum destFormat,GLint xoffset,GLint yoffset,egl::Image * dest)276 bool Texture::copy(egl::Image *source, const sw::Rect &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, egl::Image *dest)
277 {
278 	Device *device = getDevice();
279 
280 	sw::SliceRect destRect(xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0), 0);
281 	sw::SliceRect sourceSliceRect(sourceRect);
282 	bool success = device->stretchRect(source, &sourceSliceRect, dest, &destRect, false);
283 
284 	if(!success)
285 	{
286 		return error(GL_OUT_OF_MEMORY, false);
287 	}
288 
289 	return true;
290 }
291 
isMipmapFiltered() const292 bool Texture::isMipmapFiltered() const
293 {
294 	switch(mMinFilter)
295 	{
296 	case GL_NEAREST:
297 	case GL_LINEAR:
298 		return false;
299 	case GL_NEAREST_MIPMAP_NEAREST:
300 	case GL_LINEAR_MIPMAP_NEAREST:
301 	case GL_NEAREST_MIPMAP_LINEAR:
302 	case GL_LINEAR_MIPMAP_LINEAR:
303 		return true;
304 	default: UNREACHABLE(mMinFilter);
305 	}
306 
307 	return false;
308 }
309 
Texture2D(GLuint name)310 Texture2D::Texture2D(GLuint name) : Texture(name)
311 {
312 	for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
313 	{
314 		image[i] = nullptr;
315 	}
316 
317 	mSurface = nullptr;
318 
319 	mColorbufferProxy = nullptr;
320 	mProxyRefs = 0;
321 }
322 
~Texture2D()323 Texture2D::~Texture2D()
324 {
325 	for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
326 	{
327 		if(image[i])
328 		{
329 			image[i]->unbind(this);
330 			image[i] = nullptr;
331 		}
332 	}
333 
334 	if(mSurface)
335 	{
336 		mSurface->setBoundTexture(nullptr);
337 		mSurface = nullptr;
338 	}
339 
340 	mColorbufferProxy = nullptr;
341 }
342 
343 // We need to maintain a count of references to renderbuffers acting as
344 // proxies for this texture, so that we do not attempt to use a pointer
345 // to a renderbuffer proxy which has been deleted.
addProxyRef(const Renderbuffer * proxy)346 void Texture2D::addProxyRef(const Renderbuffer *proxy)
347 {
348 	mProxyRefs++;
349 }
350 
releaseProxy(const Renderbuffer * proxy)351 void Texture2D::releaseProxy(const Renderbuffer *proxy)
352 {
353 	if(mProxyRefs > 0)
354 	{
355 		mProxyRefs--;
356 	}
357 
358 	if(mProxyRefs == 0)
359 	{
360 		mColorbufferProxy = nullptr;
361 	}
362 }
363 
sweep()364 void Texture2D::sweep()
365 {
366 	int imageCount = 0;
367 
368 	for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
369 	{
370 		if(image[i] && image[i]->isChildOf(this))
371 		{
372 			if(!image[i]->hasSingleReference())
373 			{
374 				return;
375 			}
376 
377 			imageCount++;
378 		}
379 	}
380 
381 	if(imageCount == referenceCount)
382 	{
383 		destroy();
384 	}
385 }
386 
getTarget() const387 GLenum Texture2D::getTarget() const
388 {
389 	return GL_TEXTURE_2D;
390 }
391 
getWidth(GLenum target,GLint level) const392 GLsizei Texture2D::getWidth(GLenum target, GLint level) const
393 {
394 	ASSERT(target == GL_TEXTURE_2D);
395 	return image[level] ? image[level]->getWidth() : 0;
396 }
397 
getHeight(GLenum target,GLint level) const398 GLsizei Texture2D::getHeight(GLenum target, GLint level) const
399 {
400 	ASSERT(target == GL_TEXTURE_2D);
401 	return image[level] ? image[level]->getHeight() : 0;
402 }
403 
getFormat(GLenum target,GLint level) const404 GLint Texture2D::getFormat(GLenum target, GLint level) const
405 {
406 	ASSERT(target == GL_TEXTURE_2D);
407 	return image[level] ? image[level]->getFormat() : GL_NONE;
408 }
409 
getTopLevel() const410 int Texture2D::getTopLevel() const
411 {
412 	ASSERT(isSamplerComplete());
413 	int level = 0;
414 
415 	while(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[level])
416 	{
417 		level++;
418 	}
419 
420 	return level - 1;
421 }
422 
setImage(GLint level,GLsizei width,GLsizei height,GLint internalformat,GLenum format,GLenum type,GLint unpackAlignment,const void * pixels)423 void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
424 {
425 	if(image[level])
426 	{
427 		image[level]->release();
428 	}
429 
430 	image[level] = egl::Image::create(this, width, height, internalformat);
431 
432 	if(!image[level])
433 	{
434 		return error(GL_OUT_OF_MEMORY);
435 	}
436 
437 	Texture::setImage(format, type, unpackAlignment, pixels, image[level]);
438 }
439 
bindTexImage(gl::Surface * surface)440 void Texture2D::bindTexImage(gl::Surface *surface)
441 {
442 	for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
443 	{
444 		if(image[level])
445 		{
446 			image[level]->release();
447 			image[level] = nullptr;
448 		}
449 	}
450 
451 	image[0] = surface->getRenderTarget();
452 
453 	assert(!mSurface); // eglBindTexImage called before eglReleaseTexImage
454 
455 	mSurface = surface;
456 	mSurface->setBoundTexture(this);
457 }
458 
releaseTexImage()459 void Texture2D::releaseTexImage()
460 {
461 	for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
462 	{
463 		if(image[level])
464 		{
465 			image[level]->release();
466 			image[level] = nullptr;
467 		}
468 	}
469 }
470 
setCompressedImage(GLint level,GLenum format,GLsizei width,GLsizei height,GLsizei imageSize,const void * pixels)471 void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
472 {
473 	if(image[level])
474 	{
475 		image[level]->release();
476 	}
477 
478 	image[level] = egl::Image::create(this, width, height, format);
479 
480 	if(!image[level])
481 	{
482 		return error(GL_OUT_OF_MEMORY);
483 	}
484 
485 	Texture::setCompressedImage(imageSize, pixels, image[level]);
486 }
487 
subImage(GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,GLint unpackAlignment,const void * pixels)488 void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
489 {
490 	Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, image[level]);
491 }
492 
subImageCompressed(GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLsizei imageSize,const void * pixels)493 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
494 {
495 	Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, image[level]);
496 }
497 
copyImage(GLint level,GLenum format,GLint x,GLint y,GLsizei width,GLsizei height,Framebuffer * source)498 void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
499 {
500 	if(image[level])
501 	{
502 		image[level]->release();
503 	}
504 
505 	image[level] = egl::Image::create(this, width, height, format);
506 
507 	if(!image[level])
508 	{
509 		return error(GL_OUT_OF_MEMORY);
510 	}
511 
512 	if(width != 0 && height != 0)
513 	{
514 		egl::Image *renderTarget = source->getRenderTarget();
515 
516 		if(!renderTarget)
517 		{
518 			ERR("Failed to retrieve the render target.");
519 			return error(GL_OUT_OF_MEMORY);
520 		}
521 
522 		sw::Rect sourceRect = {x, y, x + width, y + height};
523 		sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());
524 
525 		copy(renderTarget, sourceRect, format, 0, 0, image[level]);
526 
527 		renderTarget->release();
528 	}
529 }
530 
copySubImage(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint x,GLint y,GLsizei width,GLsizei height,Framebuffer * source)531 void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
532 {
533 	if(!image[level])
534 	{
535 		return error(GL_INVALID_OPERATION);
536 	}
537 
538 	if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight())
539 	{
540 		return error(GL_INVALID_VALUE);
541 	}
542 
543 	egl::Image *renderTarget = source->getRenderTarget();
544 
545 	if(!renderTarget)
546 	{
547 		ERR("Failed to retrieve the render target.");
548 		return error(GL_OUT_OF_MEMORY);
549 	}
550 
551 	sw::Rect sourceRect = {x, y, x + width, y + height};
552 	sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());
553 
554 	copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, image[level]);
555 
556 	renderTarget->release();
557 }
558 
setSharedImage(egl::Image * sharedImage)559 void Texture2D::setSharedImage(egl::Image *sharedImage)
560 {
561 	sharedImage->addRef();
562 
563 	if(image[0])
564 	{
565 		image[0]->release();
566 	}
567 
568 	image[0] = sharedImage;
569 }
570 
571 // Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
isSamplerComplete() const572 bool Texture2D::isSamplerComplete() const
573 {
574 	if(!image[0])
575 	{
576 		return false;
577 	}
578 
579 	GLsizei width = image[0]->getWidth();
580 	GLsizei height = image[0]->getHeight();
581 
582 	if(width <= 0 || height <= 0)
583 	{
584 		return false;
585 	}
586 
587 	if(isMipmapFiltered())
588 	{
589 		if(!generateMipmap && !isMipmapComplete())
590 		{
591 			return false;
592 		}
593 	}
594 
595 	return true;
596 }
597 
598 // Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
isMipmapComplete() const599 bool Texture2D::isMipmapComplete() const
600 {
601 	GLsizei width = image[0]->getWidth();
602 	GLsizei height = image[0]->getHeight();
603 
604 	int q = log2(std::max(width, height));
605 
606 	for(int level = 1; level <= q; level++)
607 	{
608 		if(!image[level])
609 		{
610 			return false;
611 		}
612 
613 		if(image[level]->getFormat() != image[0]->getFormat())
614 		{
615 			return false;
616 		}
617 
618 		if(image[level]->getWidth() != std::max(1, width >> level))
619 		{
620 			return false;
621 		}
622 
623 		if(image[level]->getHeight() != std::max(1, height >> level))
624 		{
625 			return false;
626 		}
627 	}
628 
629 	return true;
630 }
631 
isCompressed(GLenum target,GLint level) const632 bool Texture2D::isCompressed(GLenum target, GLint level) const
633 {
634 	return IsCompressed(getFormat(target, level));
635 }
636 
isDepth(GLenum target,GLint level) const637 bool Texture2D::isDepth(GLenum target, GLint level) const
638 {
639 	return IsDepthTexture(getFormat(target, level));
640 }
641 
generateMipmaps()642 void Texture2D::generateMipmaps()
643 {
644 	if(!image[0])
645 	{
646 		return;   // FIXME: error?
647 	}
648 
649 	unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight()));
650 
651 	for(unsigned int i = 1; i <= q; i++)
652 	{
653 		if(image[i])
654 		{
655 			image[i]->release();
656 		}
657 
658 		image[i] = egl::Image::create(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), image[0]->getFormat());
659 
660 		if(!image[i])
661 		{
662 			return error(GL_OUT_OF_MEMORY);
663 		}
664 
665 		getDevice()->stretchRect(image[i - 1], 0, image[i], 0, true);
666 	}
667 }
668 
autoGenerateMipmaps()669 void Texture2D::autoGenerateMipmaps()
670 {
671 	if(generateMipmap && image[0]->hasDirtyContents())
672 	{
673 		generateMipmaps();
674 		image[0]->markContentsClean();
675 	}
676 }
677 
getImage(unsigned int level)678 egl::Image *Texture2D::getImage(unsigned int level)
679 {
680 	return image[level];
681 }
682 
getRenderbuffer(GLenum target,GLint level)683 Renderbuffer *Texture2D::getRenderbuffer(GLenum target, GLint level)
684 {
685 	if(target != GL_TEXTURE_2D)
686 	{
687 		return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
688 	}
689 
690 	if(!mColorbufferProxy)
691 	{
692 		mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture2D(this, level));
693 	}
694 	else
695 	{
696 		mColorbufferProxy->setLevel(level);
697 	}
698 
699 	return mColorbufferProxy;
700 }
701 
getRenderTarget(GLenum target,unsigned int level)702 egl::Image *Texture2D::getRenderTarget(GLenum target, unsigned int level)
703 {
704 	ASSERT(target == GL_TEXTURE_2D);
705 	ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
706 
707 	if(image[level])
708 	{
709 		image[level]->addRef();
710 	}
711 
712 	return image[level];
713 }
714 
isShared(GLenum target,unsigned int level) const715 bool Texture2D::isShared(GLenum target, unsigned int level) const
716 {
717 	ASSERT(target == GL_TEXTURE_2D);
718 	ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
719 
720 	if(mSurface)   // Bound to an EGLSurface
721 	{
722 		return true;
723 	}
724 
725 	if(!image[level])
726 	{
727 		return false;
728 	}
729 
730 	return image[level]->isShared();
731 }
732 
TextureExternal(GLuint name)733 TextureExternal::TextureExternal(GLuint name) : Texture2D(name)
734 {
735 	mMinFilter = GL_LINEAR;
736 	mMagFilter = GL_LINEAR;
737 	mWrapS = GL_CLAMP_TO_EDGE;
738 	mWrapT = GL_CLAMP_TO_EDGE;
739 }
740 
~TextureExternal()741 TextureExternal::~TextureExternal()
742 {
743 }
744 
getTarget() const745 GLenum TextureExternal::getTarget() const
746 {
747 	return GL_TEXTURE_EXTERNAL_OES;
748 }
749 
750 }
751 
createBackBuffer(int width,int height,sw::Format format,int multiSampleDepth)752 egl::Image *createBackBuffer(int width, int height, sw::Format format, int multiSampleDepth)
753 {
754 	if(width > es1::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE || height > es1::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE)
755 	{
756 		ERR("Invalid parameters: %dx%d", width, height);
757 		return nullptr;
758 	}
759 
760 	GLenum internalformat = sw2es::ConvertBackBufferFormat(format);
761 
762 	return egl::Image::create(width, height, internalformat, multiSampleDepth, false);
763 }
764 
createDepthStencil(int width,int height,sw::Format format,int multiSampleDepth)765 egl::Image *createDepthStencil(int width, int height, sw::Format format, int multiSampleDepth)
766 {
767 	if(width > es1::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE || height > es1::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE)
768 	{
769 		ERR("Invalid parameters: %dx%d", width, height);
770 		return nullptr;
771 	}
772 
773 	bool lockable = true;
774 
775 	switch(format)
776 	{
777 //	case sw::FORMAT_D15S1:
778 	case sw::FORMAT_D24S8:
779 	case sw::FORMAT_D24X8:
780 //	case sw::FORMAT_D24X4S4:
781 	case sw::FORMAT_D24FS8:
782 	case sw::FORMAT_D32:
783 	case sw::FORMAT_D16:
784 		lockable = false;
785 		break;
786 //	case sw::FORMAT_S8_LOCKABLE:
787 //	case sw::FORMAT_D16_LOCKABLE:
788 	case sw::FORMAT_D32F_LOCKABLE:
789 //	case sw::FORMAT_D32_LOCKABLE:
790 	case sw::FORMAT_DF24S8:
791 	case sw::FORMAT_DF16S8:
792 		lockable = true;
793 		break;
794 	default:
795 		UNREACHABLE(format);
796 	}
797 
798 	GLenum internalformat = sw2es::ConvertDepthStencilFormat(format);
799 
800 	egl::Image *surface = egl::Image::create(width, height, internalformat, multiSampleDepth, lockable);
801 
802 	if(!surface)
803 	{
804 		ERR("Out of memory");
805 		return nullptr;
806 	}
807 
808 	return surface;
809 }
810