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