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