OSDN Git Service

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