blob: ec97ee2069c9fedcd9c5122e4aa4e0ccd936a8c8 [file] [log] [blame]
Nicolas Capens0bac2852016-05-07 06:09:58 -04001// 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"
Nicolas Capens31c07a32017-06-13 23:44:13 -040026#include "common/Surface.hpp"
Nicolas Capens0bac2852016-05-07 06:09:58 -040027#include "common/debug.h"
28
29#include <algorithm>
30
31namespace es1
32{
33
34Texture::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
50Texture::~Texture()
51{
52 resource->destruct();
53}
54
55sw::Resource *Texture::getResource() const
56{
57 return resource;
58}
59
60// Returns true on successful filter state update (valid enum parameter)
61bool 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)
84bool 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)
98bool 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)
118bool 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)
138bool 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
155void Texture::setGenerateMipmap(GLboolean enable)
156{
157 generateMipmap = enable;
158}
159
160void 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
168GLenum Texture::getMinFilter() const
169{
170 return mMinFilter;
171}
172
173GLenum Texture::getMagFilter() const
174{
175 return mMagFilter;
176}
177
178GLenum Texture::getWrapS() const
179{
180 return mWrapS;
181}
182
183GLenum Texture::getWrapT() const
184{
185 return mWrapT;
186}
187
188GLfloat Texture::getMaxAnisotropy() const
189{
190 return mMaxAnisotropy;
191}
192
193GLboolean Texture::getGenerateMipmap() const
194{
195 return generateMipmap;
196}
197
198GLint Texture::getCropRectU() const
199{
200 return cropRectU;
201}
202
203GLint Texture::getCropRectV() const
204{
205 return cropRectV;
206}
207
208GLint Texture::getCropRectW() const
209{
210 return cropRectW;
211}
212
213GLint Texture::getCropRectH() const
214{
215 return cropRectH;
216}
217
218egl::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
Nicolas Capens3b4a25c2018-02-22 20:14:07 -0500230void Texture::setImage(GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400231{
232 if(pixels && image)
233 {
Nicolas Capens3b4a25c2018-02-22 20:14:07 -0500234 gl::PixelStorageModes unpackParameters;
Nicolas Capens7ada9ec2018-02-07 16:29:06 -0500235 unpackParameters.alignment = unpackAlignment;
Nicolas Capens3b4a25c2018-02-22 20:14:07 -0500236 image->loadImageData(0, 0, 0, image->getWidth(), image->getHeight(), 1, format, type, unpackParameters, pixels);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400237 }
238}
239
240void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, egl::Image *image)
241{
Nicolas Capens3b4a25c2018-02-22 20:14:07 -0500242 if(pixels && image && (imageSize > 0)) // imageSize's correlation to width and height is already validated with gl::ComputeCompressedSize() at the API level
Nicolas Capens0bac2852016-05-07 06:09:58 -0400243 {
244 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), 1, imageSize, pixels);
245 }
246}
247
Nicolas Capens3b4a25c2018-02-22 20:14:07 -0500248void Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400249{
250 if(!image)
251 {
252 return error(GL_INVALID_OPERATION);
253 }
254
Nicolas Capens0bac2852016-05-07 06:09:58 -0400255 if(pixels)
256 {
Nicolas Capens3b4a25c2018-02-22 20:14:07 -0500257 gl::PixelStorageModes unpackParameters;
Nicolas Capens7ada9ec2018-02-07 16:29:06 -0500258 unpackParameters.alignment = unpackAlignment;
Nicolas Capens3b4a25c2018-02-22 20:14:07 -0500259 image->loadImageData(xoffset, yoffset, 0, width, height, 1, format, type, unpackParameters, pixels);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400260 }
261}
262
263void 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
Nicolas Capens3b4a25c2018-02-22 20:14:07 -0500270 if(pixels && (imageSize > 0)) // imageSize's correlation to width and height is already validated with gl::ComputeCompressedSize() at the API level
Nicolas Capens0bac2852016-05-07 06:09:58 -0400271 {
272 image->loadCompressedData(xoffset, yoffset, 0, width, height, 1, imageSize, pixels);
273 }
274}
275
276bool 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
292bool 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
310Texture2D::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
323Texture2D::~Texture2D()
324{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400325 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
Nicolas Capens0bac2852016-05-07 06:09:58 -0400334 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.
346void Texture2D::addProxyRef(const Renderbuffer *proxy)
347{
348 mProxyRefs++;
349}
350
351void 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
364void 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
387GLenum Texture2D::getTarget() const
388{
389 return GL_TEXTURE_2D;
390}
391
392GLsizei Texture2D::getWidth(GLenum target, GLint level) const
393{
394 ASSERT(target == GL_TEXTURE_2D);
395 return image[level] ? image[level]->getWidth() : 0;
396}
397
398GLsizei Texture2D::getHeight(GLenum target, GLint level) const
399{
400 ASSERT(target == GL_TEXTURE_2D);
401 return image[level] ? image[level]->getHeight() : 0;
402}
403
Nicolas Capens3b4a25c2018-02-22 20:14:07 -0500404GLint Texture2D::getFormat(GLenum target, GLint level) const
Nicolas Capens0bac2852016-05-07 06:09:58 -0400405{
406 ASSERT(target == GL_TEXTURE_2D);
407 return image[level] ? image[level]->getFormat() : GL_NONE;
408}
409
Nicolas Capensb3f54e82017-12-19 13:38:18 -0500410int Texture2D::getTopLevel() const
Nicolas Capens0bac2852016-05-07 06:09:58 -0400411{
412 ASSERT(isSamplerComplete());
Nicolas Capensb3f54e82017-12-19 13:38:18 -0500413 int level = 0;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400414
Nicolas Capensb3f54e82017-12-19 13:38:18 -0500415 while(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[level])
Nicolas Capens0bac2852016-05-07 06:09:58 -0400416 {
Nicolas Capensb3f54e82017-12-19 13:38:18 -0500417 level++;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400418 }
419
Nicolas Capensb3f54e82017-12-19 13:38:18 -0500420 return level - 1;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400421}
422
Nicolas Capens3b4a25c2018-02-22 20:14:07 -0500423void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400424{
425 if(image[level])
426 {
427 image[level]->release();
428 }
429
Nicolas Capens3b4a25c2018-02-22 20:14:07 -0500430 image[level] = egl::Image::create(this, width, height, internalformat);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400431
432 if(!image[level])
433 {
434 return error(GL_OUT_OF_MEMORY);
435 }
436
Nicolas Capens3b4a25c2018-02-22 20:14:07 -0500437 Texture::setImage(format, type, unpackAlignment, pixels, image[level]);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400438}
439
Nicolas Capens31c07a32017-06-13 23:44:13 -0400440void Texture2D::bindTexImage(gl::Surface *surface)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400441{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400442 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
Alexis Hetu5efe6112019-02-20 17:02:14 -0500453 assert(!mSurface); // eglBindTexImage called before eglReleaseTexImage
454
Nicolas Capens0bac2852016-05-07 06:09:58 -0400455 mSurface = surface;
456 mSurface->setBoundTexture(this);
457}
458
459void Texture2D::releaseTexImage()
460{
461 for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
462 {
463 if(image[level])
464 {
465 image[level]->release();
466 image[level] = nullptr;
467 }
468 }
469}
470
471void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
472{
473 if(image[level])
474 {
475 image[level]->release();
476 }
477
Nicolas Capens3b4a25c2018-02-22 20:14:07 -0500478 image[level] = egl::Image::create(this, width, height, format);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400479
480 if(!image[level])
481 {
482 return error(GL_OUT_OF_MEMORY);
483 }
484
485 Texture::setCompressedImage(imageSize, pixels, image[level]);
486}
487
Nicolas Capens3b4a25c2018-02-22 20:14:07 -0500488void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400489{
Nicolas Capens3b4a25c2018-02-22 20:14:07 -0500490 Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, image[level]);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400491}
492
493void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
494{
495 Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, image[level]);
496}
497
498void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
499{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400500 if(image[level])
501 {
502 image[level]->release();
503 }
504
Nicolas Capens3b4a25c2018-02-22 20:14:07 -0500505 image[level] = egl::Image::create(this, width, height, format);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400506
507 if(!image[level])
508 {
509 return error(GL_OUT_OF_MEMORY);
510 }
511
512 if(width != 0 && height != 0)
513 {
Nicolas Capensf3980442018-06-05 10:47:46 -0400514 egl::Image *renderTarget = source->getRenderTarget();
515
516 if(!renderTarget)
517 {
518 ERR("Failed to retrieve the render target.");
519 return error(GL_OUT_OF_MEMORY);
520 }
521
Nicolas Capens0bac2852016-05-07 06:09:58 -0400522 sw::Rect sourceRect = {x, y, x + width, y + height};
523 sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());
524
525 copy(renderTarget, sourceRect, format, 0, 0, image[level]);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400526
Nicolas Capensf3980442018-06-05 10:47:46 -0400527 renderTarget->release();
528 }
Nicolas Capens0bac2852016-05-07 06:09:58 -0400529}
530
531void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
532{
533 if(!image[level])
534 {
535 return error(GL_INVALID_OPERATION);
536 }
537
538 if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight())
539 {
540 return error(GL_INVALID_VALUE);
541 }
542
543 egl::Image *renderTarget = source->getRenderTarget();
544
545 if(!renderTarget)
546 {
547 ERR("Failed to retrieve the render target.");
548 return error(GL_OUT_OF_MEMORY);
549 }
550
551 sw::Rect sourceRect = {x, y, x + width, y + height};
552 sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());
553
554 copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, image[level]);
555
556 renderTarget->release();
557}
558
Nicolas Capens58df2f62016-06-07 14:48:56 -0400559void Texture2D::setSharedImage(egl::Image *sharedImage)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400560{
561 sharedImage->addRef();
562
563 if(image[0])
564 {
565 image[0]->release();
566 }
567
568 image[0] = sharedImage;
569}
570
571// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
572bool Texture2D::isSamplerComplete() const
573{
574 if(!image[0])
575 {
576 return false;
577 }
578
579 GLsizei width = image[0]->getWidth();
580 GLsizei height = image[0]->getHeight();
581
582 if(width <= 0 || height <= 0)
583 {
584 return false;
585 }
586
587 if(isMipmapFiltered())
588 {
589 if(!generateMipmap && !isMipmapComplete())
590 {
591 return false;
592 }
593 }
594
595 return true;
596}
597
598// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
599bool Texture2D::isMipmapComplete() const
600{
601 GLsizei width = image[0]->getWidth();
602 GLsizei height = image[0]->getHeight();
603
604 int q = log2(std::max(width, height));
605
606 for(int level = 1; level <= q; level++)
607 {
608 if(!image[level])
609 {
610 return false;
611 }
612
613 if(image[level]->getFormat() != image[0]->getFormat())
614 {
615 return false;
616 }
617
Nicolas Capens0bac2852016-05-07 06:09:58 -0400618 if(image[level]->getWidth() != std::max(1, width >> level))
619 {
620 return false;
621 }
622
623 if(image[level]->getHeight() != std::max(1, height >> level))
624 {
625 return false;
626 }
627 }
628
629 return true;
630}
631
632bool Texture2D::isCompressed(GLenum target, GLint level) const
633{
634 return IsCompressed(getFormat(target, level));
635}
636
637bool Texture2D::isDepth(GLenum target, GLint level) const
638{
639 return IsDepthTexture(getFormat(target, level));
640}
641
642void Texture2D::generateMipmaps()
643{
644 if(!image[0])
645 {
646 return; // FIXME: error?
647 }
648
649 unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight()));
650
651 for(unsigned int i = 1; i <= q; i++)
652 {
653 if(image[i])
654 {
655 image[i]->release();
656 }
657
Nicolas Capens3b4a25c2018-02-22 20:14:07 -0500658 image[i] = egl::Image::create(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), image[0]->getFormat());
Nicolas Capens0bac2852016-05-07 06:09:58 -0400659
660 if(!image[i])
661 {
662 return error(GL_OUT_OF_MEMORY);
663 }
664
665 getDevice()->stretchRect(image[i - 1], 0, image[i], 0, true);
666 }
667}
668
669void Texture2D::autoGenerateMipmaps()
670{
Nicolas Capens73e18c12017-11-28 13:31:35 -0500671 if(generateMipmap && image[0]->hasDirtyContents())
Nicolas Capens0bac2852016-05-07 06:09:58 -0400672 {
673 generateMipmaps();
Nicolas Capens73e18c12017-11-28 13:31:35 -0500674 image[0]->markContentsClean();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400675 }
676}
677
678egl::Image *Texture2D::getImage(unsigned int level)
679{
680 return image[level];
681}
682
Nicolas Capens0ccc71d2018-03-23 10:13:06 -0400683Renderbuffer *Texture2D::getRenderbuffer(GLenum target, GLint level)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400684{
685 if(target != GL_TEXTURE_2D)
686 {
687 return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
688 }
689
690 if(!mColorbufferProxy)
691 {
Nicolas Capens0ccc71d2018-03-23 10:13:06 -0400692 mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture2D(this, level));
693 }
694 else
695 {
696 mColorbufferProxy->setLevel(level);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400697 }
698
699 return mColorbufferProxy;
700}
701
702egl::Image *Texture2D::getRenderTarget(GLenum target, unsigned int level)
703{
704 ASSERT(target == GL_TEXTURE_2D);
705 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
706
707 if(image[level])
708 {
709 image[level]->addRef();
710 }
711
712 return image[level];
713}
714
715bool Texture2D::isShared(GLenum target, unsigned int level) const
716{
717 ASSERT(target == GL_TEXTURE_2D);
718 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
719
720 if(mSurface) // Bound to an EGLSurface
721 {
722 return true;
723 }
724
725 if(!image[level])
726 {
727 return false;
728 }
729
730 return image[level]->isShared();
731}
732
733TextureExternal::TextureExternal(GLuint name) : Texture2D(name)
734{
735 mMinFilter = GL_LINEAR;
736 mMagFilter = GL_LINEAR;
737 mWrapS = GL_CLAMP_TO_EDGE;
738 mWrapT = GL_CLAMP_TO_EDGE;
739}
740
741TextureExternal::~TextureExternal()
742{
743}
744
745GLenum TextureExternal::getTarget() const
746{
747 return GL_TEXTURE_EXTERNAL_OES;
748}
749
750}
751
Nicolas Capens96699f12017-07-05 17:00:23 -0400752egl::Image *createBackBuffer(int width, int height, sw::Format format, int multiSampleDepth)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400753{
Nicolas Capens96699f12017-07-05 17:00:23 -0400754 if(width > es1::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE || height > es1::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400755 {
756 ERR("Invalid parameters: %dx%d", width, height);
Nicolas Capens96699f12017-07-05 17:00:23 -0400757 return nullptr;
758 }
759
Nicolas Capens3e5f6fd2018-02-26 17:47:06 -0500760 GLenum internalformat = sw2es::ConvertBackBufferFormat(format);
761
762 return egl::Image::create(width, height, internalformat, multiSampleDepth, false);
Nicolas Capens96699f12017-07-05 17:00:23 -0400763}
764
765egl::Image *createDepthStencil(int width, int height, sw::Format format, int multiSampleDepth)
766{
767 if(width > es1::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE || height > es1::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE)
768 {
769 ERR("Invalid parameters: %dx%d", width, height);
770 return nullptr;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400771 }
772
773 bool lockable = true;
774
775 switch(format)
776 {
777// case sw::FORMAT_D15S1:
778 case sw::FORMAT_D24S8:
779 case sw::FORMAT_D24X8:
780// case sw::FORMAT_D24X4S4:
781 case sw::FORMAT_D24FS8:
782 case sw::FORMAT_D32:
783 case sw::FORMAT_D16:
784 lockable = false;
785 break;
786// case sw::FORMAT_S8_LOCKABLE:
787// case sw::FORMAT_D16_LOCKABLE:
788 case sw::FORMAT_D32F_LOCKABLE:
789// case sw::FORMAT_D32_LOCKABLE:
790 case sw::FORMAT_DF24S8:
791 case sw::FORMAT_DF16S8:
792 lockable = true;
793 break;
794 default:
795 UNREACHABLE(format);
796 }
797
Nicolas Capens3e5f6fd2018-02-26 17:47:06 -0500798 GLenum internalformat = sw2es::ConvertDepthStencilFormat(format);
799
800 egl::Image *surface = egl::Image::create(width, height, internalformat, multiSampleDepth, lockable);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400801
802 if(!surface)
803 {
804 ERR("Out of memory");
805 return nullptr;
806 }
807
808 return surface;
809}