OSDN Git Service

Rename the GLES2 folder to OpenGL.
[android-x86/external-swiftshader.git] / src / OpenGL / libGLES_CM / 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 and TextureCubeMap. Implements GL texture objects and related\r
14 // 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 es1\r
29 {\r
30 \r
31 Texture::Texture(GLuint id) : RefCountObject(id)\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         mMaxAnisotropy = 1.0f;\r
38 \r
39         resource = new sw::Resource(0);\r
40 }\r
41 \r
42 Texture::~Texture()\r
43 {\r
44         resource->destruct();\r
45 }\r
46 \r
47 sw::Resource *Texture::getResource() const\r
48 {\r
49         return resource;\r
50 }\r
51 \r
52 // Returns true on successful filter state update (valid enum parameter)\r
53 bool Texture::setMinFilter(GLenum filter)\r
54 {\r
55     switch(filter)\r
56     {\r
57     case GL_NEAREST_MIPMAP_NEAREST:\r
58     case GL_LINEAR_MIPMAP_NEAREST:\r
59     case GL_NEAREST_MIPMAP_LINEAR:\r
60     case GL_LINEAR_MIPMAP_LINEAR:\r
61         if(getTarget() == GL_TEXTURE_EXTERNAL_OES)\r
62         {\r
63             return false;\r
64         }\r
65         // Fall through\r
66     case GL_NEAREST:\r
67     case GL_LINEAR:\r
68         mMinFilter = filter;\r
69         return true;\r
70     default:\r
71         return false;\r
72     }\r
73 }\r
74 \r
75 // Returns true on successful filter state update (valid enum parameter)\r
76 bool Texture::setMagFilter(GLenum filter)\r
77 {\r
78     switch(filter)\r
79     {\r
80     case GL_NEAREST:\r
81     case GL_LINEAR:\r
82         mMagFilter = filter;\r
83         return true;\r
84     default:\r
85         return false;\r
86     }\r
87 }\r
88 \r
89 // Returns true on successful wrap state update (valid enum parameter)\r
90 bool Texture::setWrapS(GLenum wrap)\r
91 {\r
92     switch(wrap)\r
93     {\r
94     case GL_REPEAT:\r
95     case GL_MIRRORED_REPEAT_OES:\r
96         if(getTarget() == GL_TEXTURE_EXTERNAL_OES)\r
97         {\r
98             return false;\r
99         }\r
100         // Fall through\r
101     case GL_CLAMP_TO_EDGE:\r
102         mWrapS = wrap;\r
103         return true;\r
104     default:\r
105         return false;\r
106     }\r
107 }\r
108 \r
109 // Returns true on successful wrap state update (valid enum parameter)\r
110 bool Texture::setWrapT(GLenum wrap)\r
111 {\r
112     switch(wrap)\r
113     {\r
114     case GL_REPEAT:\r
115     case GL_MIRRORED_REPEAT_OES:\r
116         if(getTarget() == GL_TEXTURE_EXTERNAL_OES)\r
117         {\r
118             return false;\r
119         }\r
120         // Fall through\r
121     case GL_CLAMP_TO_EDGE:\r
122          mWrapT = wrap;\r
123          return true;\r
124     default:\r
125         return false;\r
126     }\r
127 }\r
128 \r
129 // Returns true on successful max anisotropy update (valid anisotropy value)\r
130 bool Texture::setMaxAnisotropy(float textureMaxAnisotropy)\r
131 {\r
132     textureMaxAnisotropy = std::min(textureMaxAnisotropy, MAX_TEXTURE_MAX_ANISOTROPY);\r
133 \r
134     if(textureMaxAnisotropy < 1.0f)\r
135     {\r
136         return false;\r
137     }\r
138     \r
139         if(mMaxAnisotropy != textureMaxAnisotropy)\r
140     {\r
141         mMaxAnisotropy = textureMaxAnisotropy;\r
142     }\r
143 \r
144     return true;\r
145 }\r
146 \r
147 GLenum Texture::getMinFilter() const\r
148 {\r
149     return mMinFilter;\r
150 }\r
151 \r
152 GLenum Texture::getMagFilter() const\r
153 {\r
154     return mMagFilter;\r
155 }\r
156 \r
157 GLenum Texture::getWrapS() const\r
158 {\r
159     return mWrapS;\r
160 }\r
161 \r
162 GLenum Texture::getWrapT() const\r
163 {\r
164     return mWrapT;\r
165 }\r
166 \r
167 GLfloat Texture::getMaxAnisotropy() const\r
168 {\r
169     return mMaxAnisotropy;\r
170 }\r
171 \r
172 egl::Image *Texture::createSharedImage(GLenum target, unsigned int level)\r
173 {\r
174     egl::Image *image = getRenderTarget(target, level);   // Increments reference count\r
175 \r
176     if(image)\r
177     {\r
178         image->markShared();\r
179     }\r
180 \r
181     return image;\r
182 }\r
183 \r
184 void Texture::setImage(GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image)\r
185 {\r
186     if(pixels && image)\r
187     {\r
188                 image->loadImageData(0, 0, image->getWidth(), image->getHeight(), format, type, unpackAlignment, pixels);\r
189     }\r
190 }\r
191 \r
192 void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, egl::Image *image)\r
193 {\r
194     if(pixels && image)\r
195     {\r
196                 image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), imageSize, pixels);\r
197     }\r
198 }\r
199 \r
200 void Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image)\r
201 {\r
202         if(!image)\r
203         {\r
204                 return error(GL_INVALID_OPERATION);\r
205         }\r
206 \r
207     if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight())\r
208     {\r
209         return error(GL_INVALID_VALUE);\r
210     }\r
211 \r
212     if(IsCompressed(image->getFormat()))\r
213     {\r
214         return error(GL_INVALID_OPERATION);\r
215     }\r
216 \r
217     if(format != image->getFormat())\r
218     {\r
219         return error(GL_INVALID_OPERATION);\r
220     }\r
221 \r
222     if(pixels)\r
223     {\r
224         image->loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels);\r
225     }\r
226 }\r
227 \r
228 void Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, egl::Image *image)\r
229 {\r
230         if(!image)\r
231         {\r
232                 return error(GL_INVALID_OPERATION);\r
233         }\r
234 \r
235     if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight())\r
236     {\r
237         return error(GL_INVALID_VALUE);\r
238     }\r
239 \r
240     if(format != image->getFormat())\r
241     {\r
242         return error(GL_INVALID_OPERATION);\r
243     }\r
244 \r
245     if(pixels)\r
246     {\r
247                 image->loadCompressedData(xoffset, yoffset, width, height, imageSize, pixels);\r
248     }\r
249 }\r
250 \r
251 bool Texture::copy(egl::Image *source, const sw::Rect &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, egl::Image *dest)\r
252 {\r
253     Device *device = getDevice();\r
254         \r
255     sw::Rect destRect = {xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0)};\r
256     bool success = device->stretchRect(source, &sourceRect, dest, &destRect, false);\r
257 \r
258     if(!success)\r
259     {\r
260         return error(GL_OUT_OF_MEMORY, false);\r
261     }\r
262 \r
263     return true;\r
264 }\r
265 \r
266 bool Texture::isMipmapFiltered() const\r
267 {\r
268         switch(mMinFilter)\r
269     {\r
270     case GL_NEAREST:\r
271     case GL_LINEAR:\r
272         return false;\r
273     case GL_NEAREST_MIPMAP_NEAREST:\r
274     case GL_LINEAR_MIPMAP_NEAREST:\r
275     case GL_NEAREST_MIPMAP_LINEAR:\r
276     case GL_LINEAR_MIPMAP_LINEAR:\r
277         return true;\r
278     default: UNREACHABLE();\r
279     }\r
280 \r
281         return false;\r
282 }\r
283 \r
284 Texture2D::Texture2D(GLuint id) : Texture(id)\r
285 {\r
286         for(int i = 0; i < MIPMAP_LEVELS; i++)\r
287         {\r
288                 image[i] = 0;\r
289         }\r
290 \r
291     mSurface = NULL;\r
292 \r
293         mColorbufferProxy = NULL;\r
294         mProxyRefs = 0;\r
295 }\r
296 \r
297 Texture2D::~Texture2D()\r
298 {\r
299         resource->lock(sw::DESTRUCT);\r
300 \r
301         for(int i = 0; i < MIPMAP_LEVELS; i++)\r
302         {\r
303                 if(image[i])\r
304                 {\r
305                         image[i]->unbind();\r
306                         image[i] = 0;\r
307                 }\r
308         }\r
309 \r
310         resource->unlock();\r
311 \r
312     if(mSurface)\r
313     {\r
314         mSurface->setBoundTexture(NULL);\r
315         mSurface = NULL;\r
316     }\r
317 \r
318         mColorbufferProxy = NULL;\r
319 }\r
320 \r
321 // We need to maintain a count of references to renderbuffers acting as \r
322 // proxies for this texture, so that we do not attempt to use a pointer \r
323 // to a renderbuffer proxy which has been deleted.\r
324 void Texture2D::addProxyRef(const Renderbuffer *proxy)\r
325 {\r
326     mProxyRefs++;\r
327 }\r
328 \r
329 void Texture2D::releaseProxy(const Renderbuffer *proxy)\r
330 {\r
331     if(mProxyRefs > 0)\r
332         {\r
333         mProxyRefs--;\r
334         }\r
335 \r
336     if(mProxyRefs == 0)\r
337         {\r
338                 mColorbufferProxy = NULL;\r
339         }\r
340 }\r
341 \r
342 GLenum Texture2D::getTarget() const\r
343 {\r
344     return GL_TEXTURE_2D;\r
345 }\r
346 \r
347 GLsizei Texture2D::getWidth(GLenum target, GLint level) const\r
348 {\r
349         ASSERT(target == GL_TEXTURE_2D);\r
350     return image[level] ? image[level]->getWidth() : 0;\r
351 }\r
352 \r
353 GLsizei Texture2D::getHeight(GLenum target, GLint level) const\r
354 {\r
355         ASSERT(target == GL_TEXTURE_2D);\r
356     return image[level] ? image[level]->getHeight() : 0;\r
357 }\r
358 \r
359 GLenum Texture2D::getFormat(GLenum target, GLint level) const\r
360 {\r
361         ASSERT(target == GL_TEXTURE_2D);\r
362     return image[level] ? image[level]->getFormat() : 0;\r
363 }\r
364 \r
365 GLenum Texture2D::getType(GLenum target, GLint level) const\r
366 {\r
367         ASSERT(target == GL_TEXTURE_2D);\r
368     return image[level] ? image[level]->getType() : 0;\r
369 }\r
370 \r
371 sw::Format Texture2D::getInternalFormat(GLenum target, GLint level) const\r
372 {\r
373         ASSERT(target == GL_TEXTURE_2D);\r
374         return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;\r
375 }\r
376 \r
377 int Texture2D::getLevelCount() const\r
378 {\r
379         ASSERT(isSamplerComplete());\r
380         int levels = 0;\r
381 \r
382         while(levels < MIPMAP_LEVELS && image[levels])\r
383         {\r
384                 levels++;\r
385         }\r
386 \r
387         return levels;\r
388 }\r
389 \r
390 void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)\r
391 {\r
392         if(image[level])\r
393         {\r
394                 image[level]->unbind();\r
395         }\r
396 \r
397         image[level] = new Image(this, width, height, format, type);\r
398 \r
399         if(!image[level])\r
400         {\r
401                 return error(GL_OUT_OF_MEMORY);\r
402         }\r
403 \r
404     Texture::setImage(format, type, unpackAlignment, pixels, image[level]);\r
405 }\r
406 \r
407 void Texture2D::bindTexImage(egl::Surface *surface)\r
408 {\r
409     GLenum format;\r
410 \r
411     switch(surface->getInternalFormat())\r
412     {\r
413     case sw::FORMAT_A8R8G8B8:\r
414         format = GL_RGBA;\r
415         break;\r
416     case sw::FORMAT_X8R8G8B8:\r
417         format = GL_RGB;\r
418         break;\r
419     default:\r
420         UNIMPLEMENTED();\r
421         return;\r
422     }\r
423 \r
424         for(int level = 0; level < MIPMAP_LEVELS; level++)\r
425         {\r
426                 if(image[level])\r
427                 {\r
428                         image[level]->unbind();\r
429                         image[level] = 0;\r
430                 }\r
431         }\r
432 \r
433         image[0] = surface->getRenderTarget();\r
434 \r
435     mSurface = surface;\r
436     mSurface->setBoundTexture(this);\r
437 }\r
438 \r
439 void Texture2D::releaseTexImage()\r
440 {\r
441     for(int level = 0; level < MIPMAP_LEVELS; level++)\r
442         {\r
443                 if(image[level])\r
444                 {\r
445                         image[level]->unbind();\r
446                         image[level] = 0;\r
447                 }\r
448         }\r
449 }\r
450 \r
451 void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)\r
452 {\r
453         if(image[level])\r
454         {\r
455                 image[level]->unbind();\r
456         }\r
457 \r
458         image[level] = new Image(this, width, height, format, GL_UNSIGNED_BYTE);\r
459 \r
460         if(!image[level])\r
461         {\r
462                 return error(GL_OUT_OF_MEMORY);\r
463         }\r
464 \r
465     Texture::setCompressedImage(imageSize, pixels, image[level]);\r
466 }\r
467 \r
468 void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)\r
469 {\r
470         Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, image[level]);\r
471 }\r
472 \r
473 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)\r
474 {\r
475     Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, image[level]);\r
476 }\r
477 \r
478 void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)\r
479 {\r
480     egl::Image *renderTarget = source->getRenderTarget();\r
481 \r
482     if(!renderTarget)\r
483     {\r
484         ERR("Failed to retrieve the render target.");\r
485         return error(GL_OUT_OF_MEMORY);\r
486     }\r
487 \r
488         if(image[level])\r
489         {\r
490                 image[level]->unbind();\r
491         }\r
492 \r
493         image[level] = new Image(this, width, height, format, GL_UNSIGNED_BYTE);\r
494 \r
495         if(!image[level])\r
496         {\r
497                 return error(GL_OUT_OF_MEMORY);\r
498         }\r
499 \r
500     if(width != 0 && height != 0)\r
501     {\r
502                 sw::Rect sourceRect = {x, y, x + width, y + height};\r
503                 sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());\r
504 \r
505         copy(renderTarget, sourceRect, format, 0, 0, image[level]);\r
506     }\r
507 \r
508         renderTarget->release();\r
509 }\r
510 \r
511 void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)\r
512 {\r
513         if(!image[level])\r
514         {\r
515                 return error(GL_INVALID_OPERATION);\r
516         }\r
517 \r
518     if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight())\r
519     {\r
520         return error(GL_INVALID_VALUE);\r
521     }\r
522 \r
523     egl::Image *renderTarget = source->getRenderTarget();\r
524 \r
525     if(!renderTarget)\r
526     {\r
527         ERR("Failed to retrieve the render target.");\r
528         return error(GL_OUT_OF_MEMORY);\r
529     }\r
530 \r
531         sw::Rect sourceRect = {x, y, x + width, y + height};\r
532         sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());\r
533 \r
534         copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, image[level]);\r
535 \r
536         renderTarget->release();\r
537 }\r
538 \r
539 // Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.\r
540 bool Texture2D::isSamplerComplete() const\r
541 {\r
542         if(!image[0])\r
543         {\r
544                 return false;\r
545         }\r
546 \r
547     GLsizei width = image[0]->getWidth();\r
548     GLsizei height = image[0]->getHeight();\r
549 \r
550     if(width <= 0 || height <= 0)\r
551     {\r
552         return false;\r
553     }\r
554 \r
555     if(isMipmapFiltered())\r
556     {\r
557         if(!isMipmapComplete())\r
558         {\r
559             return false;\r
560         }\r
561     }\r
562 \r
563     return true;\r
564 }\r
565 \r
566 // Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.\r
567 bool Texture2D::isMipmapComplete() const\r
568 {\r
569     GLsizei width = image[0]->getWidth();\r
570     GLsizei height = image[0]->getHeight();\r
571 \r
572     int q = log2(std::max(width, height));\r
573 \r
574     for(int level = 1; level <= q; level++)\r
575     {\r
576                 if(!image[level])\r
577                 {\r
578                         return false;\r
579                 }\r
580 \r
581         if(image[level]->getFormat() != image[0]->getFormat())\r
582         {\r
583             return false;\r
584         }\r
585 \r
586         if(image[level]->getType() != image[0]->getType())\r
587         {\r
588             return false;\r
589         }\r
590 \r
591         if(image[level]->getWidth() != std::max(1, width >> level))\r
592         {\r
593             return false;\r
594         }\r
595 \r
596         if(image[level]->getHeight() != std::max(1, height >> level))\r
597         {\r
598             return false;\r
599         }\r
600     }\r
601 \r
602     return true;\r
603 }\r
604 \r
605 bool Texture2D::isCompressed(GLenum target, GLint level) const\r
606 {\r
607     return IsCompressed(getFormat(target, level));\r
608 }\r
609 \r
610 bool Texture2D::isDepth(GLenum target, GLint level) const\r
611 {\r
612     return IsDepthTexture(getFormat(target, level));\r
613 }\r
614 \r
615 void Texture2D::generateMipmaps()\r
616 {\r
617         if(!image[0])\r
618         {\r
619                 return;   // FIXME: error?\r
620         }\r
621 \r
622     unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight()));\r
623     \r
624         for(unsigned int i = 1; i <= q; i++)\r
625     {\r
626                 if(image[i])\r
627                 {\r
628                         image[i]->unbind();\r
629                 }\r
630 \r
631                 image[i] = new Image(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), image[0]->getFormat(), image[0]->getType());\r
632 \r
633                 if(!image[i])\r
634                 {\r
635                         return error(GL_OUT_OF_MEMORY);\r
636                 }\r
637 \r
638                 getDevice()->stretchRect(image[i - 1], 0, image[i], 0, true);\r
639     }\r
640 }\r
641 \r
642 egl::Image *Texture2D::getImage(unsigned int level)\r
643 {\r
644         return image[level];\r
645 }\r
646 \r
647 Renderbuffer *Texture2D::getRenderbuffer(GLenum target)\r
648 {\r
649     if(target != GL_TEXTURE_2D)\r
650     {\r
651         return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);\r
652     }\r
653 \r
654     if(mColorbufferProxy == NULL)\r
655     {\r
656         mColorbufferProxy = new Renderbuffer(id(), new RenderbufferTexture2D(this));\r
657     }\r
658 \r
659     return mColorbufferProxy;\r
660 }\r
661 \r
662 egl::Image *Texture2D::getRenderTarget(GLenum target, unsigned int level)\r
663 {\r
664     ASSERT(target == GL_TEXTURE_2D);\r
665         ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);\r
666 \r
667         if(image[level])\r
668         {\r
669                 image[level]->addRef();\r
670         }\r
671 \r
672         return image[level];\r
673 }\r
674 \r
675 bool Texture2D::isShared(GLenum target, unsigned int level) const\r
676 {\r
677     ASSERT(target == GL_TEXTURE_2D);\r
678     ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);\r
679 \r
680     if(mSurface)   // Bound to an EGLSurface\r
681     {\r
682         return true;\r
683     }\r
684 \r
685     if(!image[level])\r
686     {\r
687         return false;\r
688     }\r
689 \r
690     return image[level]->isShared();\r
691 }\r
692 \r
693 TextureExternal::TextureExternal(GLuint id) : Texture2D(id)\r
694 {\r
695     mMinFilter = GL_LINEAR;\r
696     mMagFilter = GL_LINEAR;\r
697     mWrapS = GL_CLAMP_TO_EDGE;\r
698     mWrapT = GL_CLAMP_TO_EDGE;\r
699 }\r
700 \r
701 TextureExternal::~TextureExternal()\r
702 {\r
703 }\r
704 \r
705 GLenum TextureExternal::getTarget() const\r
706 {\r
707     return GL_TEXTURE_EXTERNAL_OES;\r
708 }\r
709 \r
710 void TextureExternal::setImage(Image *sharedImage)\r
711 {\r
712     if(image[0])\r
713     {\r
714         image[0]->release();\r
715     }\r
716 \r
717     sharedImage->addRef();\r
718     image[0] = sharedImage;\r
719 }\r
720 \r
721 }\r
722 \r
723 // Exported functions for use by EGL\r
724 extern "C"\r
725 {\r
726         es1::Image *createBackBuffer(int width, int height, const egl::Config *config)\r
727         {\r
728                 if(config)\r
729                 {\r
730                         return new es1::Image(0, width, height, config->mAlphaSize ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE);\r
731                 }\r
732 \r
733                 return 0;\r
734         }\r
735 \r
736         es1::Image *createDepthStencil(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)\r
737         {\r
738                 if(width == 0 || height == 0 || height > OUTLINE_RESOLUTION)\r
739                 {\r
740                         ERR("Invalid parameters");\r
741                         return 0;\r
742                 }\r
743                 \r
744                 bool lockable = true;\r
745 \r
746                 switch(format)\r
747                 {\r
748         //      case sw::FORMAT_D15S1:\r
749                 case sw::FORMAT_D24S8:\r
750                 case sw::FORMAT_D24X8:\r
751         //      case sw::FORMAT_D24X4S4:\r
752                 case sw::FORMAT_D24FS8:\r
753                 case sw::FORMAT_D32:\r
754                 case sw::FORMAT_D16:\r
755                         lockable = false;\r
756                         break;\r
757         //      case sw::FORMAT_S8_LOCKABLE:\r
758         //      case sw::FORMAT_D16_LOCKABLE:\r
759                 case sw::FORMAT_D32F_LOCKABLE:\r
760         //      case sw::FORMAT_D32_LOCKABLE:\r
761                 case sw::FORMAT_DF24S8:\r
762                 case sw::FORMAT_DF16S8:\r
763                         lockable = true;\r
764                         break;\r
765                 default:\r
766                         UNREACHABLE();\r
767                 }\r
768 \r
769                 es1::Image *surface = new es1::Image(0, width, height, format, multiSampleDepth, lockable, true);\r
770 \r
771                 if(!surface)\r
772                 {\r
773                         ERR("Out of memory");\r
774                         return 0;\r
775                 }\r
776 \r
777                 return surface;\r
778         }\r
779 }\r