1#include "precompiled.h"
2//
3// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
4// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Texture.cpp: Implements the gl::Texture class and its derived classes
9// Texture2D and TextureCubeMap. Implements GL texture objects and related
10// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
11
12#include "libGLESv2/Texture.h"
13
14#include "libGLESv2/main.h"
15#include "common/mathutil.h"
16#include "common/utilities.h"
17#include "libGLESv2/formatutils.h"
18#include "libGLESv2/Renderbuffer.h"
19#include "libGLESv2/renderer/Image.h"
20#include "libGLESv2/renderer/Renderer.h"
21#include "libGLESv2/renderer/TextureStorage.h"
22#include "libEGL/Surface.h"
23#include "libGLESv2/Buffer.h"
24#include "libGLESv2/renderer/BufferStorage.h"
25#include "libGLESv2/renderer/RenderTarget.h"
26
27namespace gl
28{
29
30bool IsMipmapFiltered(const SamplerState &samplerState)
31{
32    switch (samplerState.minFilter)
33    {
34      case GL_NEAREST:
35      case GL_LINEAR:
36        return false;
37      case GL_NEAREST_MIPMAP_NEAREST:
38      case GL_LINEAR_MIPMAP_NEAREST:
39      case GL_NEAREST_MIPMAP_LINEAR:
40      case GL_LINEAR_MIPMAP_LINEAR:
41        return true;
42      default: UNREACHABLE();
43        return false;
44    }
45}
46
47bool IsRenderTargetUsage(GLenum usage)
48{
49    return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
50}
51
52Texture::Texture(rx::Renderer *renderer, GLuint id, GLenum target) : RefCountObject(id)
53{
54    mRenderer = renderer;
55
56    mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
57    mSamplerState.magFilter = GL_LINEAR;
58    mSamplerState.wrapS = GL_REPEAT;
59    mSamplerState.wrapT = GL_REPEAT;
60    mSamplerState.wrapR = GL_REPEAT;
61    mSamplerState.maxAnisotropy = 1.0f;
62    mSamplerState.baseLevel = 0;
63    mSamplerState.maxLevel = 1000;
64    mSamplerState.minLod = -1000.0f;
65    mSamplerState.maxLod = 1000.0f;
66    mSamplerState.compareMode = GL_NONE;
67    mSamplerState.compareFunc = GL_LEQUAL;
68    mSamplerState.swizzleRed = GL_RED;
69    mSamplerState.swizzleGreen = GL_GREEN;
70    mSamplerState.swizzleBlue = GL_BLUE;
71    mSamplerState.swizzleAlpha = GL_ALPHA;
72    mUsage = GL_NONE;
73
74    mDirtyImages = true;
75
76    mImmutable = false;
77
78    mTarget = target;
79}
80
81Texture::~Texture()
82{
83}
84
85GLenum Texture::getTarget() const
86{
87    return mTarget;
88}
89
90void Texture::addProxyRef(const FramebufferAttachment *proxy)
91{
92    mRenderbufferProxies.addRef(proxy);
93}
94
95void Texture::releaseProxy(const FramebufferAttachment *proxy)
96{
97    mRenderbufferProxies.release(proxy);
98}
99
100void Texture::setMinFilter(GLenum filter)
101{
102    mSamplerState.minFilter = filter;
103}
104
105void Texture::setMagFilter(GLenum filter)
106{
107    mSamplerState.magFilter = filter;
108}
109
110void Texture::setWrapS(GLenum wrap)
111{
112    mSamplerState.wrapS = wrap;
113}
114
115void Texture::setWrapT(GLenum wrap)
116{
117    mSamplerState.wrapT = wrap;
118}
119
120void Texture::setWrapR(GLenum wrap)
121{
122    mSamplerState.wrapR = wrap;
123}
124
125void Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
126{
127    mSamplerState.maxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
128}
129
130void Texture::setCompareMode(GLenum mode)
131{
132    mSamplerState.compareMode = mode;
133}
134
135void Texture::setCompareFunc(GLenum func)
136{
137    mSamplerState.compareFunc = func;
138}
139
140void Texture::setSwizzleRed(GLenum swizzle)
141{
142    mSamplerState.swizzleRed = swizzle;
143}
144
145void Texture::setSwizzleGreen(GLenum swizzle)
146{
147    mSamplerState.swizzleGreen = swizzle;
148}
149
150void Texture::setSwizzleBlue(GLenum swizzle)
151{
152    mSamplerState.swizzleBlue = swizzle;
153}
154
155void Texture::setSwizzleAlpha(GLenum swizzle)
156{
157    mSamplerState.swizzleAlpha = swizzle;
158}
159
160void Texture::setBaseLevel(GLint baseLevel)
161{
162    mSamplerState.baseLevel = baseLevel;
163}
164
165void Texture::setMaxLevel(GLint maxLevel)
166{
167    mSamplerState.maxLevel = maxLevel;
168}
169
170void Texture::setMinLod(GLfloat minLod)
171{
172    mSamplerState.minLod = minLod;
173}
174
175void Texture::setMaxLod(GLfloat maxLod)
176{
177    mSamplerState.maxLod = maxLod;
178}
179
180void Texture::setUsage(GLenum usage)
181{
182    mUsage = usage;
183}
184
185GLenum Texture::getMinFilter() const
186{
187    return mSamplerState.minFilter;
188}
189
190GLenum Texture::getMagFilter() const
191{
192    return mSamplerState.magFilter;
193}
194
195GLenum Texture::getWrapS() const
196{
197    return mSamplerState.wrapS;
198}
199
200GLenum Texture::getWrapT() const
201{
202    return mSamplerState.wrapT;
203}
204
205GLenum Texture::getWrapR() const
206{
207    return mSamplerState.wrapR;
208}
209
210float Texture::getMaxAnisotropy() const
211{
212    return mSamplerState.maxAnisotropy;
213}
214
215GLenum Texture::getSwizzleRed() const
216{
217    return mSamplerState.swizzleRed;
218}
219
220GLenum Texture::getSwizzleGreen() const
221{
222    return mSamplerState.swizzleGreen;
223}
224
225GLenum Texture::getSwizzleBlue() const
226{
227    return mSamplerState.swizzleBlue;
228}
229
230GLenum Texture::getSwizzleAlpha() const
231{
232    return mSamplerState.swizzleAlpha;
233}
234
235GLint Texture::getBaseLevel() const
236{
237    return mSamplerState.baseLevel;
238}
239
240GLint Texture::getMaxLevel() const
241{
242    return mSamplerState.maxLevel;
243}
244
245GLfloat Texture::getMinLod() const
246{
247    return mSamplerState.minLod;
248}
249
250GLfloat Texture::getMaxLod() const
251{
252    return mSamplerState.maxLod;
253}
254
255bool Texture::isSwizzled() const
256{
257    return mSamplerState.swizzleRed   != GL_RED   ||
258           mSamplerState.swizzleGreen != GL_GREEN ||
259           mSamplerState.swizzleBlue  != GL_BLUE  ||
260           mSamplerState.swizzleAlpha != GL_ALPHA;
261}
262
263void Texture::getSamplerState(SamplerState *sampler)
264{
265    *sampler = mSamplerState;
266
267    // Offset the effective base level by the texture storage's top level
268    rx::TextureStorageInterface *texture = getNativeTexture();
269    int topLevel = texture ? texture->getTopLevel() : 0;
270    sampler->baseLevel = topLevel + mSamplerState.baseLevel;
271}
272
273GLenum Texture::getUsage() const
274{
275    return mUsage;
276}
277
278GLint Texture::getBaseLevelWidth() const
279{
280    const rx::Image *baseImage = getBaseLevelImage();
281    return (baseImage ? baseImage->getWidth() : 0);
282}
283
284GLint Texture::getBaseLevelHeight() const
285{
286    const rx::Image *baseImage = getBaseLevelImage();
287    return (baseImage ? baseImage->getHeight() : 0);
288}
289
290GLint Texture::getBaseLevelDepth() const
291{
292    const rx::Image *baseImage = getBaseLevelImage();
293    return (baseImage ? baseImage->getDepth() : 0);
294}
295
296// Note: "base level image" is loosely defined to be any image from the base level,
297// where in the base of 2D array textures and cube maps there are several. Don't use
298// the base level image for anything except querying texture format and size.
299GLenum Texture::getBaseLevelInternalFormat() const
300{
301    const rx::Image *baseImage = getBaseLevelImage();
302    return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
303}
304
305void Texture::setImage(const PixelUnpackState &unpack, GLenum type, const void *pixels, rx::Image *image)
306{
307    // No-op
308    if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
309    {
310        return;
311    }
312
313    // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
314    // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
315    const void *pixelData = pixels;
316
317    if (unpack.pixelBuffer.id() != 0)
318    {
319        // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
320        Buffer *pixelBuffer = unpack.pixelBuffer.get();
321        ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
322        const void *bufferData = pixelBuffer->getStorage()->getData();
323        pixelData = static_cast<const unsigned char *>(bufferData) + offset;
324    }
325
326    if (pixelData != NULL)
327    {
328        image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
329        mDirtyImages = true;
330    }
331}
332
333bool Texture::isFastUnpackable(const PixelUnpackState &unpack, GLenum sizedInternalFormat)
334{
335    return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
336}
337
338bool Texture::fastUnpackPixels(const PixelUnpackState &unpack, const void *pixels, const Box &destArea,
339                               GLenum sizedInternalFormat, GLenum type, rx::RenderTarget *destRenderTarget)
340{
341    if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
342    {
343        return true;
344    }
345
346    // In order to perform the fast copy through the shader, we must have the right format, and be able
347    // to create a render target.
348    ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
349
350    unsigned int offset = reinterpret_cast<unsigned int>(pixels);
351
352    return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
353}
354
355void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
356{
357    if (pixels != NULL)
358    {
359        image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
360        mDirtyImages = true;
361    }
362}
363
364bool Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
365                       GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels, rx::Image *image)
366{
367    const void *pixelData = pixels;
368
369    // CPU readback & copy where direct GPU copy is not supported
370    if (unpack.pixelBuffer.id() != 0)
371    {
372        Buffer *pixelBuffer = unpack.pixelBuffer.get();
373        unsigned int offset = reinterpret_cast<unsigned int>(pixels);
374        const void *bufferData = pixelBuffer->getStorage()->getData();
375        pixelData = static_cast<const unsigned char *>(bufferData) + offset;
376    }
377
378    if (pixelData != NULL)
379    {
380        image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
381        mDirtyImages = true;
382    }
383
384    return true;
385}
386
387bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
388                                 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
389{
390    if (pixels != NULL)
391    {
392        image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
393        mDirtyImages = true;
394    }
395
396    return true;
397}
398
399rx::TextureStorageInterface *Texture::getNativeTexture()
400{
401    // ensure the underlying texture is created
402    initializeStorage(false);
403
404    rx::TextureStorageInterface *storage = getBaseLevelStorage();
405    if (storage)
406    {
407        updateStorage();
408    }
409
410    return storage;
411}
412
413bool Texture::hasDirtyImages() const
414{
415    return mDirtyImages;
416}
417
418void Texture::resetDirty()
419{
420    mDirtyImages = false;
421}
422
423unsigned int Texture::getTextureSerial()
424{
425    rx::TextureStorageInterface *texture = getNativeTexture();
426    return texture ? texture->getTextureSerial() : 0;
427}
428
429bool Texture::isImmutable() const
430{
431    return mImmutable;
432}
433
434int Texture::immutableLevelCount()
435{
436    return (mImmutable ? getNativeTexture()->getStorageInstance()->getLevelCount() : 0);
437}
438
439GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
440{
441    if ((isPow2(width) && isPow2(height) && isPow2(depth)) || mRenderer->getNonPower2TextureSupport())
442    {
443        // Maximum number of levels
444        return log2(std::max(std::max(width, height), depth)) + 1;
445    }
446    else
447    {
448        // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
449        return 1;
450    }
451}
452
453int Texture::mipLevels() const
454{
455    return log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
456}
457
458Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D)
459{
460    mTexStorage = NULL;
461    mSurface = NULL;
462
463    for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
464    {
465        mImageArray[i] = renderer->createImage();
466    }
467}
468
469Texture2D::~Texture2D()
470{
471    delete mTexStorage;
472    mTexStorage = NULL;
473
474    if (mSurface)
475    {
476        mSurface->setBoundTexture(NULL);
477        mSurface = NULL;
478    }
479
480    for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
481    {
482        delete mImageArray[i];
483    }
484}
485
486GLsizei Texture2D::getWidth(GLint level) const
487{
488    if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
489        return mImageArray[level]->getWidth();
490    else
491        return 0;
492}
493
494GLsizei Texture2D::getHeight(GLint level) const
495{
496    if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
497        return mImageArray[level]->getHeight();
498    else
499        return 0;
500}
501
502GLenum Texture2D::getInternalFormat(GLint level) const
503{
504    if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
505        return mImageArray[level]->getInternalFormat();
506    else
507        return GL_NONE;
508}
509
510GLenum Texture2D::getActualFormat(GLint level) const
511{
512    if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
513        return mImageArray[level]->getActualFormat();
514    else
515        return GL_NONE;
516}
517
518void Texture2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
519{
520    releaseTexImage();
521
522    // If there currently is a corresponding storage texture image, it has these parameters
523    const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
524    const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
525    const GLenum storageFormat = getBaseLevelInternalFormat();
526
527    mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
528
529    if (mTexStorage)
530    {
531        const int storageLevels = mTexStorage->getLevelCount();
532
533        if ((level >= storageLevels && storageLevels != 0) ||
534            width != storageWidth ||
535            height != storageHeight ||
536            internalformat != storageFormat)   // Discard mismatched storage
537        {
538            for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
539            {
540                mImageArray[i]->markDirty();
541            }
542
543            delete mTexStorage;
544            mTexStorage = NULL;
545            mDirtyImages = true;
546        }
547    }
548}
549
550void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
551{
552    GLuint clientVersion = mRenderer->getCurrentClientVersion();
553    GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
554                                                                                      : GetSizedInternalFormat(format, type, clientVersion);
555    redefineImage(level, sizedInternalFormat, width, height);
556
557    bool fastUnpacked = false;
558
559    // Attempt a fast gpu copy of the pixel data to the surface
560    if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
561    {
562        // Will try to create RT storage if it does not exist
563        rx::RenderTarget *destRenderTarget = getRenderTarget(level);
564        Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
565
566        if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
567        {
568            // Ensure we don't overwrite our newly initialized data
569            mImageArray[level]->markClean();
570
571            fastUnpacked = true;
572        }
573    }
574
575    if (!fastUnpacked)
576    {
577        Texture::setImage(unpack, type, pixels, mImageArray[level]);
578    }
579}
580
581void Texture2D::bindTexImage(egl::Surface *surface)
582{
583    releaseTexImage();
584
585    GLenum internalformat = surface->getFormat();
586
587    mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
588
589    delete mTexStorage;
590    mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
591
592    mDirtyImages = true;
593    mSurface = surface;
594    mSurface->setBoundTexture(this);
595}
596
597void Texture2D::releaseTexImage()
598{
599    if (mSurface)
600    {
601        mSurface->setBoundTexture(NULL);
602        mSurface = NULL;
603
604        if (mTexStorage)
605        {
606            delete mTexStorage;
607            mTexStorage = NULL;
608        }
609
610        for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
611        {
612            mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
613        }
614    }
615}
616
617void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
618{
619    // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
620    redefineImage(level, format, width, height);
621
622    Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
623}
624
625void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
626{
627    if (isValidLevel(level))
628    {
629        rx::Image *image = mImageArray[level];
630        if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height))
631        {
632            image->markClean();
633        }
634    }
635}
636
637void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
638{
639    bool fastUnpacked = false;
640
641    if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
642    {
643        rx::RenderTarget *renderTarget = getRenderTarget(level);
644        Box destArea(xoffset, yoffset, 0, width, height, 1);
645
646        if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
647        {
648            // Ensure we don't overwrite our newly initialized data
649            mImageArray[level]->markClean();
650
651            fastUnpacked = true;
652        }
653    }
654
655    if (!fastUnpacked && Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
656    {
657        commitRect(level, xoffset, yoffset, width, height);
658    }
659}
660
661void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
662{
663    if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
664    {
665        commitRect(level, xoffset, yoffset, width, height);
666    }
667}
668
669void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
670{
671    GLuint clientVersion = mRenderer->getCurrentClientVersion();
672    GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
673                                                                              : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
674    redefineImage(level, sizedInternalFormat, width, height);
675
676    if (!mImageArray[level]->isRenderableFormat())
677    {
678        mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
679        mDirtyImages = true;
680    }
681    else
682    {
683        ensureRenderTarget();
684        mImageArray[level]->markClean();
685
686        if (width != 0 && height != 0 && isValidLevel(level))
687        {
688            gl::Rectangle sourceRect;
689            sourceRect.x = x;
690            sourceRect.width = width;
691            sourceRect.y = y;
692            sourceRect.height = height;
693
694            mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
695        }
696    }
697}
698
699void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
700{
701    // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
702    // the current level we're copying to is defined (with appropriate format, width & height)
703    bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
704
705    if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
706    {
707        mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
708        mDirtyImages = true;
709    }
710    else
711    {
712        ensureRenderTarget();
713
714        if (isValidLevel(level))
715        {
716            updateStorageLevel(level);
717
718            GLuint clientVersion = mRenderer->getCurrentClientVersion();
719
720            gl::Rectangle sourceRect;
721            sourceRect.x = x;
722            sourceRect.width = width;
723            sourceRect.y = y;
724            sourceRect.height = height;
725
726            mRenderer->copyImage(source, sourceRect,
727                                 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
728                                 xoffset, yoffset, mTexStorage, level);
729        }
730    }
731}
732
733void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
734{
735    for (int level = 0; level < levels; level++)
736    {
737        GLsizei levelWidth = std::max(1, width >> level);
738        GLsizei levelHeight = std::max(1, height >> level);
739        mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
740    }
741
742    for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
743    {
744        mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
745    }
746
747    mImmutable = true;
748
749    setCompleteTexStorage(new rx::TextureStorageInterface2D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, levels));
750}
751
752void Texture2D::setCompleteTexStorage(rx::TextureStorageInterface2D *newCompleteTexStorage)
753{
754    SafeDelete(mTexStorage);
755    mTexStorage = newCompleteTexStorage;
756
757    if (mTexStorage && mTexStorage->isManaged())
758    {
759        for (int level = 0; level < mTexStorage->getLevelCount(); level++)
760        {
761            mImageArray[level]->setManagedSurface(mTexStorage, level);
762        }
763    }
764
765    mDirtyImages = true;
766}
767
768// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
769bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
770{
771    GLsizei width = getBaseLevelWidth();
772    GLsizei height = getBaseLevelHeight();
773
774    if (width <= 0 || height <= 0)
775    {
776        return false;
777    }
778
779    if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
780    {
781        if (samplerState.magFilter != GL_NEAREST ||
782            (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
783        {
784            return false;
785        }
786    }
787
788    bool npotSupport = mRenderer->getNonPower2TextureSupport();
789
790    if (!npotSupport)
791    {
792        if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
793            (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
794        {
795            return false;
796        }
797    }
798
799    if (IsMipmapFiltered(samplerState))
800    {
801        if (!npotSupport)
802        {
803            if (!isPow2(width) || !isPow2(height))
804            {
805                return false;
806            }
807        }
808
809        if (!isMipmapComplete())
810        {
811            return false;
812        }
813    }
814
815    // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
816    // The internalformat specified for the texture arrays is a sized internal depth or
817    // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
818    // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
819    // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
820    if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0 &&
821        mRenderer->getCurrentClientVersion() > 2)
822    {
823        if (mSamplerState.compareMode == GL_NONE)
824        {
825            if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
826                mSamplerState.magFilter != GL_NEAREST)
827            {
828                return false;
829            }
830        }
831    }
832
833    return true;
834}
835
836// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
837bool Texture2D::isMipmapComplete() const
838{
839    int levelCount = mipLevels();
840
841    for (int level = 0; level < levelCount; level++)
842    {
843        if (!isLevelComplete(level))
844        {
845            return false;
846        }
847    }
848
849    return true;
850}
851
852bool Texture2D::isLevelComplete(int level) const
853{
854    if (isImmutable())
855    {
856        return true;
857    }
858
859    const rx::Image *baseImage = getBaseLevelImage();
860
861    GLsizei width = baseImage->getWidth();
862    GLsizei height = baseImage->getHeight();
863
864    if (width <= 0 || height <= 0)
865    {
866        return false;
867    }
868
869    // The base image level is complete if the width and height are positive
870    if (level == 0)
871    {
872        return true;
873    }
874
875    ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
876    rx::Image *image = mImageArray[level];
877
878    if (image->getInternalFormat() != baseImage->getInternalFormat())
879    {
880        return false;
881    }
882
883    if (image->getWidth() != std::max(1, width >> level))
884    {
885        return false;
886    }
887
888    if (image->getHeight() != std::max(1, height >> level))
889    {
890        return false;
891    }
892
893    return true;
894}
895
896bool Texture2D::isCompressed(GLint level) const
897{
898    return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
899}
900
901bool Texture2D::isDepth(GLint level) const
902{
903    return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
904}
905
906// Constructs a native texture resource from the texture images
907void Texture2D::initializeStorage(bool renderTarget)
908{
909    // Only initialize the first time this texture is used as a render target or shader resource
910    if (mTexStorage)
911    {
912        return;
913    }
914
915    // do not attempt to create storage for nonexistant data
916    if (!isLevelComplete(0))
917    {
918        return;
919    }
920
921    bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
922
923    setCompleteTexStorage(createCompleteStorage(createRenderTarget));
924    ASSERT(mTexStorage);
925
926    // flush image data to the storage
927    updateStorage();
928}
929
930rx::TextureStorageInterface2D *Texture2D::createCompleteStorage(bool renderTarget) const
931{
932    GLsizei width = getBaseLevelWidth();
933    GLsizei height = getBaseLevelHeight();
934
935    ASSERT(width > 0 && height > 0);
936
937    // use existing storage level count, when previously specified by TexStorage*D
938    GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
939
940    return new rx::TextureStorageInterface2D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, levels);
941}
942
943void Texture2D::updateStorage()
944{
945    ASSERT(mTexStorage != NULL);
946    GLint storageLevels = mTexStorage->getLevelCount();
947    for (int level = 0; level < storageLevels; level++)
948    {
949        if (mImageArray[level]->isDirty() && isLevelComplete(level))
950        {
951            updateStorageLevel(level);
952        }
953    }
954}
955
956void Texture2D::updateStorageLevel(int level)
957{
958    ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
959    ASSERT(isLevelComplete(level));
960
961    if (mImageArray[level]->isDirty())
962    {
963        commitRect(level, 0, 0, getWidth(level), getHeight(level));
964    }
965}
966
967bool Texture2D::ensureRenderTarget()
968{
969    initializeStorage(true);
970
971    if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
972    {
973        ASSERT(mTexStorage);
974        if (!mTexStorage->isRenderTarget())
975        {
976            rx::TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
977
978            if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
979            {
980                delete newRenderTargetStorage;
981                return gl::error(GL_OUT_OF_MEMORY, false);
982            }
983
984            setCompleteTexStorage(newRenderTargetStorage);
985        }
986    }
987
988    return (mTexStorage && mTexStorage->isRenderTarget());
989}
990
991void Texture2D::generateMipmaps()
992{
993    // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
994    int levelCount = mipLevels();
995    for (int level = 1; level < levelCount; level++)
996    {
997        redefineImage(level, getBaseLevelInternalFormat(),
998                      std::max(getBaseLevelWidth() >> level, 1),
999                      std::max(getBaseLevelHeight() >> level, 1));
1000    }
1001
1002    if (mTexStorage && mTexStorage->isRenderTarget())
1003    {
1004        for (int level = 1; level < levelCount; level++)
1005        {
1006            mTexStorage->generateMipmap(level);
1007
1008            mImageArray[level]->markClean();
1009        }
1010    }
1011    else
1012    {
1013        for (int level = 1; level < levelCount; level++)
1014        {
1015            mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
1016        }
1017    }
1018}
1019
1020const rx::Image *Texture2D::getBaseLevelImage() const
1021{
1022    return mImageArray[0];
1023}
1024
1025rx::TextureStorageInterface *Texture2D::getBaseLevelStorage()
1026{
1027    return mTexStorage;
1028}
1029
1030FramebufferAttachment *Texture2D::getAttachment(GLint level)
1031{
1032    FramebufferAttachment *attachment = mRenderbufferProxies.get(level, 0);
1033    if (!attachment)
1034    {
1035        attachment = new FramebufferAttachment(mRenderer, id(), new Texture2DAttachment(this, level));
1036        mRenderbufferProxies.add(level, 0, attachment);
1037    }
1038
1039    return attachment;
1040}
1041
1042unsigned int Texture2D::getRenderTargetSerial(GLint level)
1043{
1044    return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
1045}
1046
1047rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
1048{
1049    // ensure the underlying texture is created
1050    if (!ensureRenderTarget())
1051    {
1052        return NULL;
1053    }
1054
1055    updateStorageLevel(level);
1056
1057    // ensure this is NOT a depth texture
1058    if (isDepth(level))
1059    {
1060        return NULL;
1061    }
1062
1063    return mTexStorage->getRenderTarget(level);
1064}
1065
1066rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
1067{
1068    // ensure the underlying texture is created
1069    if (!ensureRenderTarget())
1070    {
1071        return NULL;
1072    }
1073
1074    updateStorageLevel(level);
1075
1076    // ensure this is actually a depth texture
1077    if (!isDepth(level))
1078    {
1079        return NULL;
1080    }
1081
1082    return mTexStorage->getRenderTarget(level);
1083}
1084
1085bool Texture2D::isValidLevel(int level) const
1086{
1087    return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
1088}
1089
1090TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
1091{
1092    mTexStorage = NULL;
1093    for (int i = 0; i < 6; i++)
1094    {
1095        for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1096        {
1097            mImageArray[i][j] = renderer->createImage();
1098        }
1099    }
1100}
1101
1102TextureCubeMap::~TextureCubeMap()
1103{
1104    for (int i = 0; i < 6; i++)
1105    {
1106        for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1107        {
1108            delete mImageArray[i][j];
1109        }
1110    }
1111
1112    delete mTexStorage;
1113    mTexStorage = NULL;
1114}
1115
1116GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1117{
1118    if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1119        return mImageArray[targetToIndex(target)][level]->getWidth();
1120    else
1121        return 0;
1122}
1123
1124GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1125{
1126    if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1127        return mImageArray[targetToIndex(target)][level]->getHeight();
1128    else
1129        return 0;
1130}
1131
1132GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1133{
1134    if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1135        return mImageArray[targetToIndex(target)][level]->getInternalFormat();
1136    else
1137        return GL_NONE;
1138}
1139
1140GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
1141{
1142    if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1143        return mImageArray[targetToIndex(target)][level]->getActualFormat();
1144    else
1145        return GL_NONE;
1146}
1147
1148void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1149{
1150    setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
1151}
1152
1153void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1154{
1155    setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
1156}
1157
1158void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1159{
1160    setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
1161}
1162
1163void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1164{
1165    setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
1166}
1167
1168void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1169{
1170    setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
1171}
1172
1173void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1174{
1175    setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
1176}
1177
1178void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1179{
1180    // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1181    int faceIndex = targetToIndex(target);
1182    redefineImage(faceIndex, level, format, width, height);
1183
1184    Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
1185}
1186
1187void TextureCubeMap::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1188{
1189    if (isValidFaceLevel(faceIndex, level))
1190    {
1191        rx::Image *image = mImageArray[faceIndex][level];
1192        if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
1193            image->markClean();
1194    }
1195}
1196
1197void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1198{
1199    int faceIndex = targetToIndex(target);
1200    if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
1201    {
1202        commitRect(faceIndex, level, xoffset, yoffset, width, height);
1203    }
1204}
1205
1206void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1207{
1208    int faceIndex = targetToIndex(target);
1209    if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
1210    {
1211        commitRect(faceIndex, level, xoffset, yoffset, width, height);
1212    }
1213}
1214
1215// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
1216bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
1217{
1218    int size = getBaseLevelWidth();
1219
1220    bool mipmapping = IsMipmapFiltered(samplerState);
1221
1222    if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
1223    {
1224        if (samplerState.magFilter != GL_NEAREST ||
1225            (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
1226        {
1227            return false;
1228        }
1229    }
1230
1231    if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
1232    {
1233        if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
1234        {
1235            return false;
1236        }
1237    }
1238
1239    if (!mipmapping)
1240    {
1241        if (!isCubeComplete())
1242        {
1243            return false;
1244        }
1245    }
1246    else
1247    {
1248        if (!isMipmapCubeComplete())   // Also tests for isCubeComplete()
1249        {
1250            return false;
1251        }
1252    }
1253
1254    return true;
1255}
1256
1257// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1258bool TextureCubeMap::isCubeComplete() const
1259{
1260    int    baseWidth  = getBaseLevelWidth();
1261    int    baseHeight = getBaseLevelHeight();
1262    GLenum baseFormat = getBaseLevelInternalFormat();
1263
1264    if (baseWidth <= 0 || baseWidth != baseHeight)
1265    {
1266        return false;
1267    }
1268
1269    for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1270    {
1271        const rx::Image &faceBaseImage = *mImageArray[faceIndex][0];
1272
1273        if (faceBaseImage.getWidth()          != baseWidth  ||
1274            faceBaseImage.getHeight()         != baseHeight ||
1275            faceBaseImage.getInternalFormat() != baseFormat )
1276        {
1277            return false;
1278        }
1279    }
1280
1281    return true;
1282}
1283
1284bool TextureCubeMap::isMipmapCubeComplete() const
1285{
1286    if (isImmutable())
1287    {
1288        return true;
1289    }
1290
1291    if (!isCubeComplete())
1292    {
1293        return false;
1294    }
1295
1296    int levelCount = mipLevels();
1297
1298    for (int face = 0; face < 6; face++)
1299    {
1300        for (int level = 1; level < levelCount; level++)
1301        {
1302            if (!isFaceLevelComplete(face, level))
1303            {
1304                return false;
1305            }
1306        }
1307    }
1308
1309    return true;
1310}
1311
1312bool TextureCubeMap::isFaceLevelComplete(int faceIndex, int level) const
1313{
1314    ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1315
1316    if (isImmutable())
1317    {
1318        return true;
1319    }
1320
1321    int baseSize = getBaseLevelWidth();
1322
1323    if (baseSize <= 0)
1324    {
1325        return false;
1326    }
1327
1328    // "isCubeComplete" checks for base level completeness and we must call that
1329    // to determine if any face at level 0 is complete. We omit that check here
1330    // to avoid re-checking cube-completeness for every face at level 0.
1331    if (level == 0)
1332    {
1333        return true;
1334    }
1335
1336    // Check that non-zero levels are consistent with the base level.
1337    const rx::Image *faceLevelImage = mImageArray[faceIndex][level];
1338
1339    if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1340    {
1341        return false;
1342    }
1343
1344    if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1345    {
1346        return false;
1347    }
1348
1349    return true;
1350}
1351
1352bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1353{
1354    return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
1355}
1356
1357bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1358{
1359    return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1360}
1361
1362void TextureCubeMap::initializeStorage(bool renderTarget)
1363{
1364    // Only initialize the first time this texture is used as a render target or shader resource
1365    if (mTexStorage)
1366    {
1367        return;
1368    }
1369
1370    // do not attempt to create storage for nonexistant data
1371    if (!isFaceLevelComplete(0, 0))
1372    {
1373        return;
1374    }
1375
1376    bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1377
1378    setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1379    ASSERT(mTexStorage);
1380
1381    // flush image data to the storage
1382    updateStorage();
1383}
1384
1385rx::TextureStorageInterfaceCube *TextureCubeMap::createCompleteStorage(bool renderTarget) const
1386{
1387    GLsizei size = getBaseLevelWidth();
1388
1389    ASSERT(size > 0);
1390
1391    // use existing storage level count, when previously specified by TexStorage*D
1392    GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1393
1394    return new rx::TextureStorageInterfaceCube(mRenderer, getBaseLevelInternalFormat(), renderTarget, size, levels);
1395}
1396
1397void TextureCubeMap::setCompleteTexStorage(rx::TextureStorageInterfaceCube *newCompleteTexStorage)
1398{
1399    SafeDelete(mTexStorage);
1400    mTexStorage = newCompleteTexStorage;
1401
1402    if (mTexStorage && mTexStorage->isManaged())
1403    {
1404        for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1405        {
1406            for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1407            {
1408                mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
1409            }
1410        }
1411    }
1412
1413    mDirtyImages = true;
1414}
1415
1416void TextureCubeMap::updateStorage()
1417{
1418    ASSERT(mTexStorage != NULL);
1419    GLint storageLevels = mTexStorage->getLevelCount();
1420    for (int face = 0; face < 6; face++)
1421    {
1422        for (int level = 0; level < storageLevels; level++)
1423        {
1424            if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1425            {
1426                updateStorageFaceLevel(face, level);
1427            }
1428        }
1429    }
1430}
1431
1432void TextureCubeMap::updateStorageFaceLevel(int faceIndex, int level)
1433{
1434    ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1435    rx::Image *image = mImageArray[faceIndex][level];
1436
1437    if (image->isDirty())
1438    {
1439        commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
1440    }
1441}
1442
1443bool TextureCubeMap::ensureRenderTarget()
1444{
1445    initializeStorage(true);
1446
1447    if (getBaseLevelWidth() > 0)
1448    {
1449        ASSERT(mTexStorage);
1450        if (!mTexStorage->isRenderTarget())
1451        {
1452            rx::TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
1453
1454            if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
1455            {
1456                delete newRenderTargetStorage;
1457                return gl::error(GL_OUT_OF_MEMORY, false);
1458            }
1459
1460            setCompleteTexStorage(newRenderTargetStorage);
1461        }
1462    }
1463
1464    return (mTexStorage && mTexStorage->isRenderTarget());
1465}
1466
1467void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1468{
1469    GLuint clientVersion = mRenderer->getCurrentClientVersion();
1470    GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1471                                                                                      : GetSizedInternalFormat(format, type, clientVersion);
1472
1473    redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1474
1475    Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
1476}
1477
1478int TextureCubeMap::targetToIndex(GLenum target)
1479{
1480    META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1481    META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1482    META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1483    META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1484    META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1485
1486    return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1487}
1488
1489void TextureCubeMap::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1490{
1491    // If there currently is a corresponding storage texture image, it has these parameters
1492    const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1493    const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1494    const GLenum storageFormat = getBaseLevelInternalFormat();
1495
1496    mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1497
1498    if (mTexStorage)
1499    {
1500        const int storageLevels = mTexStorage->getLevelCount();
1501
1502        if ((level >= storageLevels && storageLevels != 0) ||
1503            width != storageWidth ||
1504            height != storageHeight ||
1505            internalformat != storageFormat)   // Discard mismatched storage
1506        {
1507            for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1508            {
1509                for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1510                {
1511                    mImageArray[faceIndex][level]->markDirty();
1512                }
1513            }
1514
1515            delete mTexStorage;
1516            mTexStorage = NULL;
1517
1518            mDirtyImages = true;
1519        }
1520    }
1521}
1522
1523void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1524{
1525    int faceIndex = targetToIndex(target);
1526    GLuint clientVersion = mRenderer->getCurrentClientVersion();
1527    GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1528                                                                              : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
1529    redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1530
1531    if (!mImageArray[faceIndex][level]->isRenderableFormat())
1532    {
1533        mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
1534        mDirtyImages = true;
1535    }
1536    else
1537    {
1538        ensureRenderTarget();
1539        mImageArray[faceIndex][level]->markClean();
1540
1541        ASSERT(width == height);
1542
1543        if (width > 0 && isValidFaceLevel(faceIndex, level))
1544        {
1545            gl::Rectangle sourceRect;
1546            sourceRect.x = x;
1547            sourceRect.width = width;
1548            sourceRect.y = y;
1549            sourceRect.height = height;
1550
1551            mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
1552        }
1553    }
1554}
1555
1556void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1557{
1558    int faceIndex = targetToIndex(target);
1559
1560    // We can only make our texture storage to a render target if the level we're copying *to* is complete
1561    // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1562    // rely on the "getBaseLevel*" methods reliably otherwise.
1563    bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
1564
1565    if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1566    {
1567        mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
1568        mDirtyImages = true;
1569    }
1570    else
1571    {
1572        ensureRenderTarget();
1573
1574        if (isValidFaceLevel(faceIndex, level))
1575        {
1576            updateStorageFaceLevel(faceIndex, level);
1577
1578            GLuint clientVersion = mRenderer->getCurrentClientVersion();
1579
1580            gl::Rectangle sourceRect;
1581            sourceRect.x = x;
1582            sourceRect.width = width;
1583            sourceRect.y = y;
1584            sourceRect.height = height;
1585
1586            mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
1587                                 xoffset, yoffset, mTexStorage, target, level);
1588        }
1589    }
1590}
1591
1592void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1593{
1594    for (int level = 0; level < levels; level++)
1595    {
1596        GLsizei mipSize = std::max(1, size >> level);
1597        for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1598        {
1599            mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1600        }
1601    }
1602
1603    for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1604    {
1605        for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1606        {
1607            mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1608        }
1609    }
1610
1611    mImmutable = true;
1612
1613    setCompleteTexStorage(new rx::TextureStorageInterfaceCube(mRenderer, internalformat, IsRenderTargetUsage(mUsage), size, levels));
1614}
1615
1616void TextureCubeMap::generateMipmaps()
1617{
1618    // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1619    int levelCount = mipLevels();
1620    for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1621    {
1622        for (int level = 1; level < levelCount; level++)
1623        {
1624            int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1625            redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1626        }
1627    }
1628
1629    if (mTexStorage && mTexStorage->isRenderTarget())
1630    {
1631        for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1632        {
1633            for (int level = 1; level < levelCount; level++)
1634            {
1635                mTexStorage->generateMipmap(faceIndex, level);
1636
1637                mImageArray[faceIndex][level]->markClean();
1638            }
1639        }
1640    }
1641    else
1642    {
1643        for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1644        {
1645            for (int level = 1; level < levelCount; level++)
1646            {
1647                mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
1648            }
1649        }
1650    }
1651}
1652
1653const rx::Image *TextureCubeMap::getBaseLevelImage() const
1654{
1655    // Note: if we are not cube-complete, there is no single base level image that can describe all
1656    // cube faces, so this method is only well-defined for a cube-complete base level.
1657    return mImageArray[0][0];
1658}
1659
1660rx::TextureStorageInterface *TextureCubeMap::getBaseLevelStorage()
1661{
1662    return mTexStorage;
1663}
1664
1665FramebufferAttachment *TextureCubeMap::getAttachment(GLenum target, GLint level)
1666{
1667    ASSERT(!IsCubemapTextureTarget(target));
1668    int faceIndex = targetToIndex(target);
1669
1670    FramebufferAttachment *attachment = mRenderbufferProxies.get(level, faceIndex);
1671    if (!attachment)
1672    {
1673        attachment = new FramebufferAttachment(mRenderer, id(), new TextureCubeMapAttachment(this, target, level));
1674        mRenderbufferProxies.add(level, faceIndex, attachment);
1675    }
1676
1677    return attachment;
1678}
1679
1680unsigned int TextureCubeMap::getRenderTargetSerial(GLenum target, GLint level)
1681{
1682    return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
1683}
1684
1685rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
1686{
1687    ASSERT(IsCubemapTextureTarget(target));
1688
1689    // ensure the underlying texture is created
1690    if (!ensureRenderTarget())
1691    {
1692        return NULL;
1693    }
1694
1695    updateStorageFaceLevel(targetToIndex(target), level);
1696
1697    // ensure this is NOT a depth texture
1698    if (isDepth(target, level))
1699    {
1700        return NULL;
1701    }
1702
1703    return mTexStorage->getRenderTarget(target, level);
1704}
1705
1706rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1707{
1708    ASSERT(IsCubemapTextureTarget(target));
1709
1710    // ensure the underlying texture is created
1711    if (!ensureRenderTarget())
1712    {
1713        return NULL;
1714    }
1715
1716    updateStorageFaceLevel(targetToIndex(target), level);
1717
1718    // ensure this is a depth texture
1719    if (!isDepth(target, level))
1720    {
1721        return NULL;
1722    }
1723
1724    return mTexStorage->getRenderTarget(target, level);
1725}
1726
1727bool TextureCubeMap::isValidFaceLevel(int faceIndex, int level) const
1728{
1729    return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1730}
1731
1732Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
1733{
1734    mTexStorage = NULL;
1735
1736    for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1737    {
1738        mImageArray[i] = renderer->createImage();
1739    }
1740}
1741
1742Texture3D::~Texture3D()
1743{
1744    delete mTexStorage;
1745    mTexStorage = NULL;
1746
1747    for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1748    {
1749        delete mImageArray[i];
1750    }
1751}
1752
1753GLsizei Texture3D::getWidth(GLint level) const
1754{
1755    return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1756}
1757
1758GLsizei Texture3D::getHeight(GLint level) const
1759{
1760    return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1761}
1762
1763GLsizei Texture3D::getDepth(GLint level) const
1764{
1765    return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1766}
1767
1768GLenum Texture3D::getInternalFormat(GLint level) const
1769{
1770    return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1771}
1772
1773GLenum Texture3D::getActualFormat(GLint level) const
1774{
1775    return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : GL_NONE;
1776}
1777
1778bool Texture3D::isCompressed(GLint level) const
1779{
1780    return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
1781}
1782
1783bool Texture3D::isDepth(GLint level) const
1784{
1785    return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
1786}
1787
1788void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1789{
1790    GLuint clientVersion = mRenderer->getCurrentClientVersion();
1791    GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1792                                                                                      : GetSizedInternalFormat(format, type, clientVersion);
1793    redefineImage(level, sizedInternalFormat, width, height, depth);
1794
1795    bool fastUnpacked = false;
1796
1797    // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1798    if (isFastUnpackable(unpack, sizedInternalFormat))
1799    {
1800        // Will try to create RT storage if it does not exist
1801        rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1802        Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1803
1804        if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1805        {
1806            // Ensure we don't overwrite our newly initialized data
1807            mImageArray[level]->markClean();
1808
1809            fastUnpacked = true;
1810        }
1811    }
1812
1813    if (!fastUnpacked)
1814    {
1815        Texture::setImage(unpack, type, pixels, mImageArray[level]);
1816    }
1817}
1818
1819void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1820{
1821    // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1822    redefineImage(level, format, width, height, depth);
1823
1824    Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1825}
1826
1827void Texture3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1828{
1829    bool fastUnpacked = false;
1830
1831    // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1832    if (isFastUnpackable(unpack, getInternalFormat(level)))
1833    {
1834        rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1835        Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1836
1837        if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1838        {
1839            // Ensure we don't overwrite our newly initialized data
1840            mImageArray[level]->markClean();
1841
1842            fastUnpacked = true;
1843        }
1844    }
1845
1846    if (!fastUnpacked && Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, mImageArray[level]))
1847    {
1848        commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1849    }
1850}
1851
1852void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1853{
1854    if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1855    {
1856        commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1857    }
1858}
1859
1860void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1861{
1862    for (int level = 0; level < levels; level++)
1863    {
1864        GLsizei levelWidth = std::max(1, width >> level);
1865        GLsizei levelHeight = std::max(1, height >> level);
1866        GLsizei levelDepth = std::max(1, depth >> level);
1867        mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1868    }
1869
1870    for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1871    {
1872        mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1873    }
1874
1875    mImmutable = true;
1876
1877    setCompleteTexStorage(new rx::TextureStorageInterface3D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
1878}
1879
1880void Texture3D::generateMipmaps()
1881{
1882    // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1883    int levelCount = mipLevels();
1884    for (int level = 1; level < levelCount; level++)
1885    {
1886        redefineImage(level, getBaseLevelInternalFormat(),
1887                      std::max(getBaseLevelWidth() >> level, 1),
1888                      std::max(getBaseLevelHeight() >> level, 1),
1889                      std::max(getBaseLevelDepth() >> level, 1));
1890    }
1891
1892    if (mTexStorage && mTexStorage->isRenderTarget())
1893    {
1894        for (int level = 1; level < levelCount; level++)
1895        {
1896            mTexStorage->generateMipmap(level);
1897
1898            mImageArray[level]->markClean();
1899        }
1900    }
1901    else
1902    {
1903        for (int level = 1; level < levelCount; level++)
1904        {
1905            mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
1906        }
1907    }
1908}
1909
1910const rx::Image *Texture3D::getBaseLevelImage() const
1911{
1912    return mImageArray[0];
1913}
1914
1915rx::TextureStorageInterface *Texture3D::getBaseLevelStorage()
1916{
1917    return mTexStorage;
1918}
1919
1920void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1921{
1922    // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1923    // the current level we're copying to is defined (with appropriate format, width & height)
1924    bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1925
1926    if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1927    {
1928        mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1929        mDirtyImages = true;
1930    }
1931    else
1932    {
1933        ensureRenderTarget();
1934
1935        if (isValidLevel(level))
1936        {
1937            updateStorageLevel(level);
1938
1939            gl::Rectangle sourceRect;
1940            sourceRect.x = x;
1941            sourceRect.width = width;
1942            sourceRect.y = y;
1943            sourceRect.height = height;
1944
1945            GLuint clientVersion = mRenderer->getCurrentClientVersion();
1946
1947            mRenderer->copyImage(source, sourceRect,
1948                                 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
1949                                 xoffset, yoffset, zoffset, mTexStorage, level);
1950        }
1951    }
1952}
1953
1954bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
1955{
1956    GLsizei width = getBaseLevelWidth();
1957    GLsizei height = getBaseLevelHeight();
1958    GLsizei depth = getBaseLevelDepth();
1959
1960    if (width <= 0 || height <= 0 || depth <= 0)
1961    {
1962        return false;
1963    }
1964
1965    if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
1966    {
1967        if (samplerState.magFilter != GL_NEAREST ||
1968            (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
1969        {
1970            return false;
1971        }
1972    }
1973
1974    if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
1975    {
1976        return false;
1977    }
1978
1979    return true;
1980}
1981
1982bool Texture3D::isMipmapComplete() const
1983{
1984    int levelCount = mipLevels();
1985
1986    for (int level = 0; level < levelCount; level++)
1987    {
1988        if (!isLevelComplete(level))
1989        {
1990            return false;
1991        }
1992    }
1993
1994    return true;
1995}
1996
1997bool Texture3D::isLevelComplete(int level) const
1998{
1999    ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2000
2001    if (isImmutable())
2002    {
2003        return true;
2004    }
2005
2006    GLsizei width = getBaseLevelWidth();
2007    GLsizei height = getBaseLevelHeight();
2008    GLsizei depth = getBaseLevelDepth();
2009
2010    if (width <= 0 || height <= 0 || depth <= 0)
2011    {
2012        return false;
2013    }
2014
2015    if (level == 0)
2016    {
2017        return true;
2018    }
2019
2020    rx::Image *levelImage = mImageArray[level];
2021
2022    if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2023    {
2024        return false;
2025    }
2026
2027    if (levelImage->getWidth() != std::max(1, width >> level))
2028    {
2029        return false;
2030    }
2031
2032    if (levelImage->getHeight() != std::max(1, height >> level))
2033    {
2034        return false;
2035    }
2036
2037    if (levelImage->getDepth() != std::max(1, depth >> level))
2038    {
2039        return false;
2040    }
2041
2042    return true;
2043}
2044
2045FramebufferAttachment *Texture3D::getAttachment(GLint level, GLint layer)
2046{
2047    FramebufferAttachment *attachment = mRenderbufferProxies.get(level, layer);
2048    if (!attachment)
2049    {
2050        attachment = new FramebufferAttachment(mRenderer, id(), new Texture3DAttachment(this, level, layer));
2051        mRenderbufferProxies.add(level, 0, attachment);
2052    }
2053
2054    return attachment;
2055}
2056
2057unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
2058{
2059    return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
2060}
2061
2062bool Texture3D::isValidLevel(int level) const
2063{
2064    return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2065}
2066
2067void Texture3D::initializeStorage(bool renderTarget)
2068{
2069    // Only initialize the first time this texture is used as a render target or shader resource
2070    if (mTexStorage)
2071    {
2072        return;
2073    }
2074
2075    // do not attempt to create storage for nonexistant data
2076    if (!isLevelComplete(0))
2077    {
2078        return;
2079    }
2080
2081    bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2082
2083    setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2084    ASSERT(mTexStorage);
2085
2086    // flush image data to the storage
2087    updateStorage();
2088}
2089
2090rx::TextureStorageInterface3D *Texture3D::createCompleteStorage(bool renderTarget) const
2091{
2092    GLsizei width = getBaseLevelWidth();
2093    GLsizei height = getBaseLevelHeight();
2094    GLsizei depth = getBaseLevelDepth();
2095
2096    ASSERT(width > 0 && height > 0 && depth > 0);
2097
2098    // use existing storage level count, when previously specified by TexStorage*D
2099    GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2100
2101    return new rx::TextureStorageInterface3D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
2102}
2103
2104void Texture3D::setCompleteTexStorage(rx::TextureStorageInterface3D *newCompleteTexStorage)
2105{
2106    SafeDelete(mTexStorage);
2107    mTexStorage = newCompleteTexStorage;
2108    mDirtyImages = true;
2109
2110    // We do not support managed 3D storage, as that is D3D9/ES2-only
2111    ASSERT(!mTexStorage->isManaged());
2112}
2113
2114void Texture3D::updateStorage()
2115{
2116    ASSERT(mTexStorage != NULL);
2117    GLint storageLevels = mTexStorage->getLevelCount();
2118    for (int level = 0; level < storageLevels; level++)
2119    {
2120        if (mImageArray[level]->isDirty() && isLevelComplete(level))
2121        {
2122            updateStorageLevel(level);
2123        }
2124    }
2125}
2126
2127void Texture3D::updateStorageLevel(int level)
2128{
2129    ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2130    ASSERT(isLevelComplete(level));
2131
2132    if (mImageArray[level]->isDirty())
2133    {
2134        commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
2135    }
2136}
2137
2138bool Texture3D::ensureRenderTarget()
2139{
2140    initializeStorage(true);
2141
2142    if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
2143    {
2144        ASSERT(mTexStorage);
2145        if (!mTexStorage->isRenderTarget())
2146        {
2147            rx::TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
2148
2149            if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
2150            {
2151                delete newRenderTargetStorage;
2152                return gl::error(GL_OUT_OF_MEMORY, false);
2153            }
2154
2155            setCompleteTexStorage(newRenderTargetStorage);
2156        }
2157    }
2158
2159    return (mTexStorage && mTexStorage->isRenderTarget());
2160}
2161
2162rx::RenderTarget *Texture3D::getRenderTarget(GLint level)
2163{
2164    // ensure the underlying texture is created
2165    if (!ensureRenderTarget())
2166    {
2167        return NULL;
2168    }
2169
2170    updateStorageLevel(level);
2171
2172    // ensure this is NOT a depth texture
2173    if (isDepth(level))
2174    {
2175        return NULL;
2176    }
2177
2178    return mTexStorage->getRenderTarget(level);
2179}
2180
2181rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
2182{
2183    // ensure the underlying texture is created
2184    if (!ensureRenderTarget())
2185    {
2186        return NULL;
2187    }
2188
2189    updateStorage();
2190
2191    // ensure this is NOT a depth texture
2192    if (isDepth(level))
2193    {
2194        return NULL;
2195    }
2196
2197    return mTexStorage->getRenderTarget(level, layer);
2198}
2199
2200rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2201{
2202    // ensure the underlying texture is created
2203    if (!ensureRenderTarget())
2204    {
2205        return NULL;
2206    }
2207
2208    updateStorageLevel(level);
2209
2210    // ensure this is a depth texture
2211    if (!isDepth(level))
2212    {
2213        return NULL;
2214    }
2215
2216    return mTexStorage->getRenderTarget(level, layer);
2217}
2218
2219void Texture3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2220{
2221    // If there currently is a corresponding storage texture image, it has these parameters
2222    const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2223    const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2224    const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2225    const GLenum storageFormat = getBaseLevelInternalFormat();
2226
2227    mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
2228
2229    if (mTexStorage)
2230    {
2231        const int storageLevels = mTexStorage->getLevelCount();
2232
2233        if ((level >= storageLevels && storageLevels != 0) ||
2234            width != storageWidth ||
2235            height != storageHeight ||
2236            depth != storageDepth ||
2237            internalformat != storageFormat)   // Discard mismatched storage
2238        {
2239            for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2240            {
2241                mImageArray[i]->markDirty();
2242            }
2243
2244            delete mTexStorage;
2245            mTexStorage = NULL;
2246            mDirtyImages = true;
2247        }
2248    }
2249}
2250
2251void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2252{
2253    if (isValidLevel(level))
2254    {
2255        rx::Image *image = mImageArray[level];
2256        if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
2257        {
2258            image->markClean();
2259        }
2260    }
2261}
2262
2263Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
2264{
2265    mTexStorage = NULL;
2266
2267    for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2268    {
2269        mLayerCounts[level] = 0;
2270        mImageArray[level] = NULL;
2271    }
2272}
2273
2274Texture2DArray::~Texture2DArray()
2275{
2276    delete mTexStorage;
2277    mTexStorage = NULL;
2278
2279    deleteImages();
2280}
2281
2282void Texture2DArray::deleteImages()
2283{
2284    for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2285    {
2286        for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2287        {
2288            delete mImageArray[level][layer];
2289        }
2290        delete[] mImageArray[level];
2291        mImageArray[level] = NULL;
2292        mLayerCounts[level] = 0;
2293    }
2294}
2295
2296GLsizei Texture2DArray::getWidth(GLint level) const
2297{
2298    return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2299}
2300
2301GLsizei Texture2DArray::getHeight(GLint level) const
2302{
2303    return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2304}
2305
2306GLsizei Texture2DArray::getLayers(GLint level) const
2307{
2308    return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
2309}
2310
2311GLenum Texture2DArray::getInternalFormat(GLint level) const
2312{
2313    return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2314}
2315
2316GLenum Texture2DArray::getActualFormat(GLint level) const
2317{
2318    return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getActualFormat() : GL_NONE;
2319}
2320
2321bool Texture2DArray::isCompressed(GLint level) const
2322{
2323    return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
2324}
2325
2326bool Texture2DArray::isDepth(GLint level) const
2327{
2328    return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
2329}
2330
2331void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
2332{
2333    GLuint clientVersion = mRenderer->getCurrentClientVersion();
2334    GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2335                                                                                      : GetSizedInternalFormat(format, type, clientVersion);
2336    redefineImage(level, sizedInternalFormat, width, height, depth);
2337
2338    GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
2339
2340    for (int i = 0; i < depth; i++)
2341    {
2342        const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2343        Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
2344    }
2345}
2346
2347void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2348{
2349    // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2350    redefineImage(level, format, width, height, depth);
2351
2352    GLuint clientVersion = mRenderer->getCurrentClientVersion();
2353    GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
2354
2355    for (int i = 0; i < depth; i++)
2356    {
2357        const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2358        Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2359    }
2360}
2361
2362void Texture2DArray::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
2363{
2364    GLenum internalformat = getInternalFormat(level);
2365    GLuint clientVersion =  mRenderer->getCurrentClientVersion();
2366    GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
2367
2368    for (int i = 0; i < depth; i++)
2369    {
2370        int layer = zoffset + i;
2371        const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2372
2373        if (Texture::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, mImageArray[level][layer]))
2374        {
2375            commitRect(level, xoffset, yoffset, layer, width, height);
2376        }
2377    }
2378}
2379
2380void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2381{
2382    GLuint clientVersion = mRenderer->getCurrentClientVersion();
2383    GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
2384
2385    for (int i = 0; i < depth; i++)
2386    {
2387        int layer = zoffset + i;
2388        const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2389
2390        if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2391        {
2392            commitRect(level, xoffset, yoffset, layer, width, height);
2393        }
2394    }
2395}
2396
2397void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2398{
2399    deleteImages();
2400
2401    for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2402    {
2403        GLsizei levelWidth = std::max(1, width >> level);
2404        GLsizei levelHeight = std::max(1, height >> level);
2405
2406        mLayerCounts[level] = (level < levels ? depth : 0);
2407
2408        if (mLayerCounts[level] > 0)
2409        {
2410            // Create new images for this level
2411            mImageArray[level] = new rx::Image*[mLayerCounts[level]];
2412
2413            for (int layer = 0; layer < mLayerCounts[level]; layer++)
2414            {
2415                mImageArray[level][layer] = mRenderer->createImage();
2416                mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2417                                                    levelHeight, 1, true);
2418            }
2419        }
2420    }
2421
2422    mImmutable = true;
2423    setCompleteTexStorage(new rx::TextureStorageInterface2DArray(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
2424}
2425
2426void Texture2DArray::generateMipmaps()
2427{
2428    int baseWidth = getBaseLevelWidth();
2429    int baseHeight = getBaseLevelHeight();
2430    int baseDepth = getBaseLevelDepth();
2431    GLenum baseFormat = getBaseLevelInternalFormat();
2432
2433    // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2434    int levelCount = mipLevels();
2435    for (int level = 1; level < levelCount; level++)
2436    {
2437        redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2438    }
2439
2440    if (mTexStorage && mTexStorage->isRenderTarget())
2441    {
2442        for (int level = 1; level < levelCount; level++)
2443        {
2444            mTexStorage->generateMipmap(level);
2445
2446            for (int layer = 0; layer < mLayerCounts[level]; layer++)
2447            {
2448                mImageArray[level][layer]->markClean();
2449            }
2450        }
2451    }
2452    else
2453    {
2454        for (int level = 1; level < levelCount; level++)
2455        {
2456            for (int layer = 0; layer < mLayerCounts[level]; layer++)
2457            {
2458                mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2459            }
2460        }
2461    }
2462}
2463
2464const rx::Image *Texture2DArray::getBaseLevelImage() const
2465{
2466    return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
2467}
2468
2469rx::TextureStorageInterface *Texture2DArray::getBaseLevelStorage()
2470{
2471    return mTexStorage;
2472}
2473
2474void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2475{
2476    // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2477    // the current level we're copying to is defined (with appropriate format, width & height)
2478    bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2479
2480    if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
2481    {
2482        mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2483        mDirtyImages = true;
2484    }
2485    else
2486    {
2487        ensureRenderTarget();
2488
2489        if (isValidLevel(level))
2490        {
2491            updateStorageLevel(level);
2492
2493            GLuint clientVersion = mRenderer->getCurrentClientVersion();
2494
2495            gl::Rectangle sourceRect;
2496            sourceRect.x = x;
2497            sourceRect.width = width;
2498            sourceRect.y = y;
2499            sourceRect.height = height;
2500
2501            mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
2502                                 xoffset, yoffset, zoffset, mTexStorage, level);
2503        }
2504    }
2505}
2506
2507bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
2508{
2509    GLsizei width = getBaseLevelWidth();
2510    GLsizei height = getBaseLevelHeight();
2511    GLsizei depth = getLayers(0);
2512
2513    if (width <= 0 || height <= 0 || depth <= 0)
2514    {
2515        return false;
2516    }
2517
2518    if (!IsTextureFilteringSupported(getBaseLevelInternalFormat(), mRenderer))
2519    {
2520        if (samplerState.magFilter != GL_NEAREST ||
2521            (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
2522        {
2523            return false;
2524        }
2525    }
2526
2527    if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
2528    {
2529        return false;
2530    }
2531
2532    return true;
2533}
2534
2535bool Texture2DArray::isMipmapComplete() const
2536{
2537    int levelCount = mipLevels();
2538
2539    for (int level = 1; level < levelCount; level++)
2540    {
2541        if (!isLevelComplete(level))
2542        {
2543            return false;
2544        }
2545    }
2546
2547    return true;
2548}
2549
2550bool Texture2DArray::isLevelComplete(int level) const
2551{
2552    ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2553
2554    if (isImmutable())
2555    {
2556        return true;
2557    }
2558
2559    GLsizei width = getBaseLevelWidth();
2560    GLsizei height = getBaseLevelHeight();
2561    GLsizei layers = getLayers(0);
2562
2563    if (width <= 0 || height <= 0 || layers <= 0)
2564    {
2565        return false;
2566    }
2567
2568    if (level == 0)
2569    {
2570        return true;
2571    }
2572
2573    if (getInternalFormat(level) != getInternalFormat(0))
2574    {
2575        return false;
2576    }
2577
2578    if (getWidth(level) != std::max(1, width >> level))
2579    {
2580        return false;
2581    }
2582
2583    if (getHeight(level) != std::max(1, height >> level))
2584    {
2585        return false;
2586    }
2587
2588    if (getLayers(level) != layers)
2589    {
2590        return false;
2591    }
2592
2593    return true;
2594}
2595
2596FramebufferAttachment *Texture2DArray::getAttachment(GLint level, GLint layer)
2597{
2598    FramebufferAttachment *attachment = mRenderbufferProxies.get(level, layer);
2599    if (!attachment)
2600    {
2601        attachment = new FramebufferAttachment(mRenderer, id(), new Texture2DArrayAttachment(this, level, layer));
2602        mRenderbufferProxies.add(level, 0, attachment);
2603    }
2604
2605    return attachment;
2606}
2607
2608unsigned int Texture2DArray::getRenderTargetSerial(GLint level, GLint layer)
2609{
2610    return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
2611}
2612
2613bool Texture2DArray::isValidLevel(int level) const
2614{
2615    return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2616}
2617
2618void Texture2DArray::initializeStorage(bool renderTarget)
2619{
2620    // Only initialize the first time this texture is used as a render target or shader resource
2621    if (mTexStorage)
2622    {
2623        return;
2624    }
2625
2626    // do not attempt to create storage for nonexistant data
2627    if (!isLevelComplete(0))
2628    {
2629        return;
2630    }
2631
2632    bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2633
2634    setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2635    ASSERT(mTexStorage);
2636
2637    // flush image data to the storage
2638    updateStorage();
2639}
2640
2641rx::TextureStorageInterface2DArray *Texture2DArray::createCompleteStorage(bool renderTarget) const
2642{
2643    GLsizei width = getBaseLevelWidth();
2644    GLsizei height = getBaseLevelHeight();
2645    GLsizei depth = getLayers(0);
2646
2647    ASSERT(width > 0 && height > 0 && depth > 0);
2648
2649    // use existing storage level count, when previously specified by TexStorage*D
2650    GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2651
2652    return new rx::TextureStorageInterface2DArray(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
2653}
2654
2655void Texture2DArray::setCompleteTexStorage(rx::TextureStorageInterface2DArray *newCompleteTexStorage)
2656{
2657    SafeDelete(mTexStorage);
2658    mTexStorage = newCompleteTexStorage;
2659    mDirtyImages = true;
2660
2661    // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2662    ASSERT(!mTexStorage->isManaged());
2663}
2664
2665void Texture2DArray::updateStorage()
2666{
2667    ASSERT(mTexStorage != NULL);
2668    GLint storageLevels = mTexStorage->getLevelCount();
2669    for (int level = 0; level < storageLevels; level++)
2670    {
2671        if (isLevelComplete(level))
2672        {
2673            updateStorageLevel(level);
2674        }
2675    }
2676}
2677
2678void Texture2DArray::updateStorageLevel(int level)
2679{
2680    ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2681    ASSERT(isLevelComplete(level));
2682
2683    for (int layer = 0; layer < mLayerCounts[level]; layer++)
2684    {
2685        ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2686        if (mImageArray[level][layer]->isDirty())
2687        {
2688            commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2689        }
2690    }
2691}
2692
2693bool Texture2DArray::ensureRenderTarget()
2694{
2695    initializeStorage(true);
2696
2697    if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
2698    {
2699        ASSERT(mTexStorage);
2700        if (!mTexStorage->isRenderTarget())
2701        {
2702            rx::TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2703
2704            if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
2705            {
2706                delete newRenderTargetStorage;
2707                return gl::error(GL_OUT_OF_MEMORY, false);
2708            }
2709
2710            setCompleteTexStorage(newRenderTargetStorage);
2711        }
2712    }
2713
2714    return (mTexStorage && mTexStorage->isRenderTarget());
2715}
2716
2717rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
2718{
2719    // ensure the underlying texture is created
2720    if (!ensureRenderTarget())
2721    {
2722        return NULL;
2723    }
2724
2725    updateStorageLevel(level);
2726
2727    // ensure this is NOT a depth texture
2728    if (isDepth(level))
2729    {
2730        return NULL;
2731    }
2732
2733    return mTexStorage->getRenderTarget(level, layer);
2734}
2735
2736rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2737{
2738    // ensure the underlying texture is created
2739    if (!ensureRenderTarget())
2740    {
2741        return NULL;
2742    }
2743
2744    updateStorageLevel(level);
2745
2746    // ensure this is a depth texture
2747    if (!isDepth(level))
2748    {
2749        return NULL;
2750    }
2751
2752    return mTexStorage->getRenderTarget(level, layer);
2753}
2754
2755void Texture2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2756{
2757    // If there currently is a corresponding storage texture image, it has these parameters
2758    const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2759    const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2760    const int storageDepth = getLayers(0);
2761    const GLenum storageFormat = getBaseLevelInternalFormat();
2762
2763    for (int layer = 0; layer < mLayerCounts[level]; layer++)
2764    {
2765        delete mImageArray[level][layer];
2766    }
2767    delete[] mImageArray[level];
2768    mImageArray[level] = NULL;
2769    mLayerCounts[level] = depth;
2770
2771    if (depth > 0)
2772    {
2773        mImageArray[level] = new rx::Image*[depth]();
2774
2775        for (int layer = 0; layer < mLayerCounts[level]; layer++)
2776        {
2777            mImageArray[level][layer] = mRenderer->createImage();
2778            mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2779        }
2780    }
2781
2782    if (mTexStorage)
2783    {
2784        const int storageLevels = mTexStorage->getLevelCount();
2785
2786        if ((level >= storageLevels && storageLevels != 0) ||
2787            width != storageWidth ||
2788            height != storageHeight ||
2789            depth != storageDepth ||
2790            internalformat != storageFormat)   // Discard mismatched storage
2791        {
2792            for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2793            {
2794                for (int layer = 0; layer < mLayerCounts[level]; layer++)
2795                {
2796                    mImageArray[level][layer]->markDirty();
2797                }
2798            }
2799
2800            delete mTexStorage;
2801            mTexStorage = NULL;
2802            mDirtyImages = true;
2803        }
2804    }
2805}
2806
2807void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2808{
2809    if (isValidLevel(level) && layerTarget < getLayers(level))
2810    {
2811        rx::Image *image = mImageArray[level][layerTarget];
2812        if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2813        {
2814            image->markClean();
2815        }
2816    }
2817}
2818
2819}
2820