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 "libEGL/Surface.h"
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 egl::Image::UnpackInfo unpackInfo;
235 unpackInfo.alignment = unpackAlignment;
236 image->loadImageData(0, 0, 0, image->getWidth(), image->getHeight(), 1, format, type, unpackInfo, 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)
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(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(xoffset, yoffset, 0, width, height, 1, format, type, unpackInfo, pixels);
275 }
276 }
277
subImageCompressed(GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLsizei imageSize,const void * pixels,egl::Image * image)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
copy(egl::Image * source,const sw::Rect & sourceRect,GLenum destFormat,GLint xoffset,GLint yoffset,egl::Image * dest)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
isMipmapFiltered() const317 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
Texture2D(GLuint name)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
~Texture2D()348 Texture2D::~Texture2D()
349 {
350 resource->lock(sw::DESTRUCT);
351
352 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
353 {
354 if(image[i])
355 {
356 image[i]->unbind(this);
357 image[i] = nullptr;
358 }
359 }
360
361 resource->unlock();
362
363 if(mSurface)
364 {
365 mSurface->setBoundTexture(nullptr);
366 mSurface = nullptr;
367 }
368
369 mColorbufferProxy = nullptr;
370 }
371
372 // We need to maintain a count of references to renderbuffers acting as
373 // proxies for this texture, so that we do not attempt to use a pointer
374 // to a renderbuffer proxy which has been deleted.
addProxyRef(const Renderbuffer * proxy)375 void Texture2D::addProxyRef(const Renderbuffer *proxy)
376 {
377 mProxyRefs++;
378 }
379
releaseProxy(const Renderbuffer * proxy)380 void Texture2D::releaseProxy(const Renderbuffer *proxy)
381 {
382 if(mProxyRefs > 0)
383 {
384 mProxyRefs--;
385 }
386
387 if(mProxyRefs == 0)
388 {
389 mColorbufferProxy = nullptr;
390 }
391 }
392
sweep()393 void Texture2D::sweep()
394 {
395 int imageCount = 0;
396
397 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
398 {
399 if(image[i] && image[i]->isChildOf(this))
400 {
401 if(!image[i]->hasSingleReference())
402 {
403 return;
404 }
405
406 imageCount++;
407 }
408 }
409
410 if(imageCount == referenceCount)
411 {
412 destroy();
413 }
414 }
415
getTarget() const416 GLenum Texture2D::getTarget() const
417 {
418 return GL_TEXTURE_2D;
419 }
420
getWidth(GLenum target,GLint level) const421 GLsizei Texture2D::getWidth(GLenum target, GLint level) const
422 {
423 ASSERT(target == GL_TEXTURE_2D);
424 return image[level] ? image[level]->getWidth() : 0;
425 }
426
getHeight(GLenum target,GLint level) const427 GLsizei Texture2D::getHeight(GLenum target, GLint level) const
428 {
429 ASSERT(target == GL_TEXTURE_2D);
430 return image[level] ? image[level]->getHeight() : 0;
431 }
432
getFormat(GLenum target,GLint level) const433 GLenum Texture2D::getFormat(GLenum target, GLint level) const
434 {
435 ASSERT(target == GL_TEXTURE_2D);
436 return image[level] ? image[level]->getFormat() : GL_NONE;
437 }
438
getType(GLenum target,GLint level) const439 GLenum Texture2D::getType(GLenum target, GLint level) const
440 {
441 ASSERT(target == GL_TEXTURE_2D);
442 return image[level] ? image[level]->getType() : GL_NONE;
443 }
444
getInternalFormat(GLenum target,GLint level) const445 sw::Format Texture2D::getInternalFormat(GLenum target, GLint level) const
446 {
447 ASSERT(target == GL_TEXTURE_2D);
448 return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
449 }
450
getLevelCount() const451 int Texture2D::getLevelCount() const
452 {
453 ASSERT(isSamplerComplete());
454 int levels = 0;
455
456 while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[levels])
457 {
458 levels++;
459 }
460
461 return levels;
462 }
463
setImage(GLint level,GLsizei width,GLsizei height,GLenum format,GLenum type,GLint unpackAlignment,const void * pixels)464 void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
465 {
466 if(image[level])
467 {
468 image[level]->release();
469 }
470
471 image[level] = new egl::Image(this, width, height, format, type);
472
473 if(!image[level])
474 {
475 return error(GL_OUT_OF_MEMORY);
476 }
477
478 Texture::setImage(format, type, unpackAlignment, pixels, image[level]);
479 }
480
bindTexImage(egl::Surface * surface)481 void Texture2D::bindTexImage(egl::Surface *surface)
482 {
483 GLenum format;
484
485 switch(surface->getInternalFormat())
486 {
487 case sw::FORMAT_A8R8G8B8:
488 format = GL_BGRA_EXT;
489 break;
490 case sw::FORMAT_A8B8G8R8:
491 format = GL_RGBA;
492 break;
493 case sw::FORMAT_X8B8G8R8:
494 case sw::FORMAT_X8R8G8B8:
495 format = GL_RGB;
496 break;
497 default:
498 UNIMPLEMENTED();
499 return;
500 }
501
502 for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
503 {
504 if(image[level])
505 {
506 image[level]->release();
507 image[level] = nullptr;
508 }
509 }
510
511 image[0] = surface->getRenderTarget();
512
513 mSurface = surface;
514 mSurface->setBoundTexture(this);
515 }
516
releaseTexImage()517 void Texture2D::releaseTexImage()
518 {
519 for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
520 {
521 if(image[level])
522 {
523 image[level]->release();
524 image[level] = nullptr;
525 }
526 }
527 }
528
setCompressedImage(GLint level,GLenum format,GLsizei width,GLsizei height,GLsizei imageSize,const void * pixels)529 void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
530 {
531 if(image[level])
532 {
533 image[level]->release();
534 }
535
536 image[level] = new egl::Image(this, width, height, format, GL_UNSIGNED_BYTE);
537
538 if(!image[level])
539 {
540 return error(GL_OUT_OF_MEMORY);
541 }
542
543 Texture::setCompressedImage(imageSize, pixels, image[level]);
544 }
545
subImage(GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,GLint unpackAlignment,const void * pixels)546 void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
547 {
548 Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, image[level]);
549 }
550
subImageCompressed(GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLsizei imageSize,const void * pixels)551 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
552 {
553 Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, image[level]);
554 }
555
copyImage(GLint level,GLenum format,GLint x,GLint y,GLsizei width,GLsizei height,Framebuffer * source)556 void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
557 {
558 egl::Image *renderTarget = source->getRenderTarget();
559
560 if(!renderTarget)
561 {
562 ERR("Failed to retrieve the render target.");
563 return error(GL_OUT_OF_MEMORY);
564 }
565
566 if(image[level])
567 {
568 image[level]->release();
569 }
570
571 image[level] = new egl::Image(this, width, height, format, GL_UNSIGNED_BYTE);
572
573 if(!image[level])
574 {
575 return error(GL_OUT_OF_MEMORY);
576 }
577
578 if(width != 0 && height != 0)
579 {
580 sw::Rect sourceRect = {x, y, x + width, y + height};
581 sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());
582
583 copy(renderTarget, sourceRect, format, 0, 0, image[level]);
584 }
585
586 renderTarget->release();
587 }
588
copySubImage(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint x,GLint y,GLsizei width,GLsizei height,Framebuffer * source)589 void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
590 {
591 if(!image[level])
592 {
593 return error(GL_INVALID_OPERATION);
594 }
595
596 if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight())
597 {
598 return error(GL_INVALID_VALUE);
599 }
600
601 egl::Image *renderTarget = source->getRenderTarget();
602
603 if(!renderTarget)
604 {
605 ERR("Failed to retrieve the render target.");
606 return error(GL_OUT_OF_MEMORY);
607 }
608
609 sw::Rect sourceRect = {x, y, x + width, y + height};
610 sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());
611
612 copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, image[level]);
613
614 renderTarget->release();
615 }
616
setImage(egl::Image * sharedImage)617 void Texture2D::setImage(egl::Image *sharedImage)
618 {
619 sharedImage->addRef();
620
621 if(image[0])
622 {
623 image[0]->release();
624 }
625
626 image[0] = sharedImage;
627 }
628
629 // Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
isSamplerComplete() const630 bool Texture2D::isSamplerComplete() const
631 {
632 if(!image[0])
633 {
634 return false;
635 }
636
637 GLsizei width = image[0]->getWidth();
638 GLsizei height = image[0]->getHeight();
639
640 if(width <= 0 || height <= 0)
641 {
642 return false;
643 }
644
645 if(isMipmapFiltered())
646 {
647 if(!generateMipmap && !isMipmapComplete())
648 {
649 return false;
650 }
651 }
652
653 return true;
654 }
655
656 // Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
isMipmapComplete() const657 bool Texture2D::isMipmapComplete() const
658 {
659 GLsizei width = image[0]->getWidth();
660 GLsizei height = image[0]->getHeight();
661
662 int q = log2(std::max(width, height));
663
664 for(int level = 1; level <= q; level++)
665 {
666 if(!image[level])
667 {
668 return false;
669 }
670
671 if(image[level]->getFormat() != image[0]->getFormat())
672 {
673 return false;
674 }
675
676 if(image[level]->getType() != image[0]->getType())
677 {
678 return false;
679 }
680
681 if(image[level]->getWidth() != std::max(1, width >> level))
682 {
683 return false;
684 }
685
686 if(image[level]->getHeight() != std::max(1, height >> level))
687 {
688 return false;
689 }
690 }
691
692 return true;
693 }
694
isCompressed(GLenum target,GLint level) const695 bool Texture2D::isCompressed(GLenum target, GLint level) const
696 {
697 return IsCompressed(getFormat(target, level));
698 }
699
isDepth(GLenum target,GLint level) const700 bool Texture2D::isDepth(GLenum target, GLint level) const
701 {
702 return IsDepthTexture(getFormat(target, level));
703 }
704
generateMipmaps()705 void Texture2D::generateMipmaps()
706 {
707 if(!image[0])
708 {
709 return; // FIXME: error?
710 }
711
712 unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight()));
713
714 for(unsigned int i = 1; i <= q; i++)
715 {
716 if(image[i])
717 {
718 image[i]->release();
719 }
720
721 image[i] = new egl::Image(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), image[0]->getFormat(), image[0]->getType());
722
723 if(!image[i])
724 {
725 return error(GL_OUT_OF_MEMORY);
726 }
727
728 getDevice()->stretchRect(image[i - 1], 0, image[i], 0, true);
729 }
730 }
731
autoGenerateMipmaps()732 void Texture2D::autoGenerateMipmaps()
733 {
734 if(generateMipmap && image[0]->hasDirtyMipmaps())
735 {
736 generateMipmaps();
737 image[0]->cleanMipmaps();
738 }
739 }
740
getImage(unsigned int level)741 egl::Image *Texture2D::getImage(unsigned int level)
742 {
743 return image[level];
744 }
745
getRenderbuffer(GLenum target)746 Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
747 {
748 if(target != GL_TEXTURE_2D)
749 {
750 return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
751 }
752
753 if(!mColorbufferProxy)
754 {
755 mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture2D(this));
756 }
757
758 return mColorbufferProxy;
759 }
760
getRenderTarget(GLenum target,unsigned int level)761 egl::Image *Texture2D::getRenderTarget(GLenum target, unsigned int level)
762 {
763 ASSERT(target == GL_TEXTURE_2D);
764 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
765
766 if(image[level])
767 {
768 image[level]->addRef();
769 }
770
771 return image[level];
772 }
773
isShared(GLenum target,unsigned int level) const774 bool Texture2D::isShared(GLenum target, unsigned int level) const
775 {
776 ASSERT(target == GL_TEXTURE_2D);
777 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
778
779 if(mSurface) // Bound to an EGLSurface
780 {
781 return true;
782 }
783
784 if(!image[level])
785 {
786 return false;
787 }
788
789 return image[level]->isShared();
790 }
791
TextureExternal(GLuint name)792 TextureExternal::TextureExternal(GLuint name) : Texture2D(name)
793 {
794 mMinFilter = GL_LINEAR;
795 mMagFilter = GL_LINEAR;
796 mWrapS = GL_CLAMP_TO_EDGE;
797 mWrapT = GL_CLAMP_TO_EDGE;
798 }
799
~TextureExternal()800 TextureExternal::~TextureExternal()
801 {
802 }
803
getTarget() const804 GLenum TextureExternal::getTarget() const
805 {
806 return GL_TEXTURE_EXTERNAL_OES;
807 }
808
809 }
810
createBackBuffer(int width,int height,const egl::Config * config)811 egl::Image *createBackBuffer(int width, int height, const egl::Config *config)
812 {
813 if(config)
814 {
815 return new egl::Image(width, height, config->mRenderTargetFormat, config->mSamples, false);
816 }
817
818 return nullptr;
819 }
820
createDepthStencil(unsigned int width,unsigned int height,sw::Format format,int multiSampleDepth,bool discard)821 egl::Image *createDepthStencil(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)
822 {
823 if(height > sw::OUTLINE_RESOLUTION)
824 {
825 ERR("Invalid parameters: %dx%d", width, height);
826 return 0;
827 }
828
829 bool lockable = true;
830
831 switch(format)
832 {
833 // case sw::FORMAT_D15S1:
834 case sw::FORMAT_D24S8:
835 case sw::FORMAT_D24X8:
836 // case sw::FORMAT_D24X4S4:
837 case sw::FORMAT_D24FS8:
838 case sw::FORMAT_D32:
839 case sw::FORMAT_D16:
840 lockable = false;
841 break;
842 // case sw::FORMAT_S8_LOCKABLE:
843 // case sw::FORMAT_D16_LOCKABLE:
844 case sw::FORMAT_D32F_LOCKABLE:
845 // case sw::FORMAT_D32_LOCKABLE:
846 case sw::FORMAT_DF24S8:
847 case sw::FORMAT_DF16S8:
848 lockable = true;
849 break;
850 default:
851 UNREACHABLE(format);
852 }
853
854 egl::Image *surface = new egl::Image(width, height, format, multiSampleDepth, lockable);
855
856 if(!surface)
857 {
858 ERR("Out of memory");
859 return nullptr;
860 }
861
862 return surface;
863 }
864