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