~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/ThirdParty/ANGLE/src/libGLESv2/Texture.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
 
3
// Use of this source code is governed by a BSD-style license that can be
 
4
// found in the LICENSE file.
 
5
//
 
6
 
 
7
// Texture.cpp: Implements the gl::Texture class and its derived classes
 
8
// Texture2D and TextureCubeMap. Implements GL texture objects and related
 
9
// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
 
10
 
 
11
#include "libGLESv2/Texture.h"
 
12
 
 
13
#include <d3dx9tex.h>
 
14
 
 
15
#include <algorithm>
 
16
#include <intrin.h>
 
17
 
 
18
#include "common/debug.h"
 
19
 
 
20
#include "libEGL/Display.h"
 
21
 
 
22
#include "libGLESv2/main.h"
 
23
#include "libGLESv2/mathutil.h"
 
24
#include "libGLESv2/utilities.h"
 
25
#include "libGLESv2/Blit.h"
 
26
#include "libGLESv2/Framebuffer.h"
 
27
 
 
28
namespace gl
 
29
{
 
30
unsigned int TextureStorage::mCurrentTextureSerial = 1;
 
31
 
 
32
static D3DFORMAT ConvertTextureFormatType(GLenum format, GLenum type)
 
33
{
 
34
    if (IsDepthTexture(format))
 
35
    {
 
36
        return D3DFMT_INTZ;
 
37
    }
 
38
    else if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
 
39
             format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
 
40
    {
 
41
        return D3DFMT_DXT1;
 
42
    }
 
43
    else if (format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE)
 
44
    {
 
45
        return D3DFMT_DXT3;
 
46
    }
 
47
    else if (format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE)
 
48
    {
 
49
        return D3DFMT_DXT5;
 
50
    }
 
51
    else if (type == GL_FLOAT)
 
52
    {
 
53
        return D3DFMT_A32B32G32R32F;
 
54
    }
 
55
    else if (type == GL_HALF_FLOAT_OES)
 
56
    {
 
57
        return D3DFMT_A16B16G16R16F;
 
58
    }
 
59
    else if (type == GL_UNSIGNED_BYTE)
 
60
    {
 
61
        if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
 
62
        {
 
63
            return D3DFMT_L8;
 
64
        }
 
65
        else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
 
66
        {
 
67
            return D3DFMT_A8L8;
 
68
        }
 
69
        else if (format == GL_RGB)
 
70
        {
 
71
            return D3DFMT_X8R8G8B8;
 
72
        }
 
73
 
 
74
        return D3DFMT_A8R8G8B8;
 
75
    }
 
76
 
 
77
    return D3DFMT_A8R8G8B8;
 
78
}
 
79
 
 
80
static bool IsTextureFormatRenderable(D3DFORMAT format)
 
81
{
 
82
    if (format == D3DFMT_INTZ)
 
83
    {
 
84
        return true;
 
85
    }
 
86
    switch(format)
 
87
    {
 
88
      case D3DFMT_L8:
 
89
      case D3DFMT_A8L8:
 
90
      case D3DFMT_DXT1:
 
91
      case D3DFMT_DXT3:
 
92
      case D3DFMT_DXT5:
 
93
        return false;
 
94
      case D3DFMT_A8R8G8B8:
 
95
      case D3DFMT_X8R8G8B8:
 
96
      case D3DFMT_A16B16G16R16F:
 
97
      case D3DFMT_A32B32G32R32F:
 
98
        return true;
 
99
      default:
 
100
        UNREACHABLE();
 
101
    }
 
102
 
 
103
    return false;
 
104
}
 
105
 
 
106
static inline DWORD GetTextureUsage(D3DFORMAT d3dfmt, GLenum glusage, bool forceRenderable)
 
107
{
 
108
    DWORD d3dusage = 0;
 
109
 
 
110
    if (d3dfmt == D3DFMT_INTZ)
 
111
    {
 
112
        d3dusage |= D3DUSAGE_DEPTHSTENCIL;
 
113
    }
 
114
    else if(forceRenderable || (IsTextureFormatRenderable(d3dfmt) && (glusage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE)))
 
115
    {
 
116
        d3dusage |= D3DUSAGE_RENDERTARGET;
 
117
    }
 
118
    return d3dusage;
 
119
}
 
120
 
 
121
Image::Image()
 
122
{
 
123
    mWidth = 0; 
 
124
    mHeight = 0;
 
125
    mFormat = GL_NONE;
 
126
    mType = GL_UNSIGNED_BYTE;
 
127
 
 
128
    mSurface = NULL;
 
129
 
 
130
    mDirty = false;
 
131
 
 
132
    mD3DPool = D3DPOOL_SYSTEMMEM;
 
133
    mD3DFormat = D3DFMT_UNKNOWN;
 
134
}
 
135
 
 
136
Image::~Image()
 
137
{
 
138
    if (mSurface)
 
139
    {
 
140
        mSurface->Release();
 
141
    }
 
142
}
 
143
 
 
144
bool Image::redefine(GLenum format, GLsizei width, GLsizei height, GLenum type, bool forceRelease)
 
145
{
 
146
    if (mWidth != width ||
 
147
        mHeight != height ||
 
148
        mFormat != format ||
 
149
        mType != type ||
 
150
        forceRelease)
 
151
    {
 
152
        mWidth = width;
 
153
        mHeight = height;
 
154
        mFormat = format;
 
155
        mType = type;
 
156
        // compute the d3d format that will be used
 
157
        mD3DFormat = ConvertTextureFormatType(mFormat, mType);
 
158
 
 
159
        if (mSurface)
 
160
        {
 
161
            mSurface->Release();
 
162
            mSurface = NULL;
 
163
        }
 
164
 
 
165
        return true;
 
166
    }
 
167
 
 
168
    return false;
 
169
}
 
170
 
 
171
void Image::createSurface()
 
172
{
 
173
    if(mSurface)
 
174
    {
 
175
        return;
 
176
    }
 
177
 
 
178
    IDirect3DTexture9 *newTexture = NULL;
 
179
    IDirect3DSurface9 *newSurface = NULL;
 
180
    const D3DPOOL poolToUse = D3DPOOL_SYSTEMMEM;
 
181
    const D3DFORMAT d3dFormat = getD3DFormat();
 
182
    ASSERT(d3dFormat != D3DFMT_INTZ); // We should never get here for depth textures
 
183
 
 
184
    if (mWidth != 0 && mHeight != 0)
 
185
    {
 
186
        int levelToFetch = 0;
 
187
        GLsizei requestWidth = mWidth;
 
188
        GLsizei requestHeight = mHeight;
 
189
        if (IsCompressed(mFormat) && (mWidth % 4 != 0 || mHeight % 4 != 0))
 
190
        {
 
191
            bool isMult4 = false;
 
192
            int upsampleCount = 0;
 
193
            while (!isMult4)
 
194
            {
 
195
                requestWidth <<= 1;
 
196
                requestHeight <<= 1;
 
197
                upsampleCount++;
 
198
                if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
 
199
                {
 
200
                    isMult4 = true;
 
201
                }
 
202
            }
 
203
            levelToFetch = upsampleCount;
 
204
        }
 
205
 
 
206
        HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, d3dFormat,
 
207
                                                    poolToUse, &newTexture, NULL);
 
208
 
 
209
        if (FAILED(result))
 
210
        {
 
211
            ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
 
212
            ERR("Creating image surface failed.");
 
213
            return error(GL_OUT_OF_MEMORY);
 
214
        }
 
215
 
 
216
        newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
 
217
        newTexture->Release();
 
218
    }
 
219
 
 
220
    mSurface = newSurface;
 
221
    mDirty = false;
 
222
    mD3DPool = poolToUse;
 
223
}
 
224
 
 
225
HRESULT Image::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect)
 
226
{
 
227
    createSurface();
 
228
 
 
229
    HRESULT result = D3DERR_INVALIDCALL;
 
230
 
 
231
    if (mSurface)
 
232
    {
 
233
        result = mSurface->LockRect(lockedRect, rect, 0);
 
234
        ASSERT(SUCCEEDED(result));
 
235
 
 
236
        mDirty = true;
 
237
    }
 
238
 
 
239
    return result;
 
240
}
 
241
 
 
242
void Image::unlock()
 
243
{
 
244
    if (mSurface)
 
245
    {
 
246
        HRESULT result = mSurface->UnlockRect();
 
247
        ASSERT(SUCCEEDED(result));
 
248
    }
 
249
}
 
250
 
 
251
bool Image::isRenderableFormat() const
 
252
{    
 
253
    return IsTextureFormatRenderable(getD3DFormat());
 
254
}
 
255
 
 
256
D3DFORMAT Image::getD3DFormat() const
 
257
{
 
258
    // this should only happen if the image hasn't been redefined first
 
259
    // which would be a bug by the caller
 
260
    ASSERT(mD3DFormat != D3DFMT_UNKNOWN);
 
261
 
 
262
    return mD3DFormat;
 
263
}
 
264
 
 
265
IDirect3DSurface9 *Image::getSurface()
 
266
{
 
267
    createSurface();
 
268
 
 
269
    return mSurface;
 
270
}
 
271
 
 
272
void Image::setManagedSurface(IDirect3DSurface9 *surface)
 
273
{
 
274
    if (mSurface)
 
275
    {
 
276
        D3DXLoadSurfaceFromSurface(surface, NULL, NULL, mSurface, NULL, NULL, D3DX_FILTER_BOX, 0);
 
277
        mSurface->Release();
 
278
    }
 
279
 
 
280
    D3DSURFACE_DESC desc;
 
281
    surface->GetDesc(&desc);
 
282
    ASSERT(desc.Pool == D3DPOOL_MANAGED);
 
283
 
 
284
    mSurface = surface;
 
285
    mD3DPool = desc.Pool;
 
286
}
 
287
 
 
288
void Image::updateSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
 
289
{
 
290
    IDirect3DSurface9 *sourceSurface = getSurface();
 
291
 
 
292
    if (sourceSurface && sourceSurface != destSurface)
 
293
    {
 
294
        RECT rect;
 
295
        rect.left = xoffset;
 
296
        rect.top = yoffset;
 
297
        rect.right = xoffset + width;
 
298
        rect.bottom = yoffset + height;
 
299
 
 
300
        if (mD3DPool == D3DPOOL_MANAGED)
 
301
        {
 
302
            HRESULT result = D3DXLoadSurfaceFromSurface(destSurface, NULL, &rect, sourceSurface, NULL, &rect, D3DX_FILTER_BOX, 0);
 
303
            ASSERT(SUCCEEDED(result));
 
304
        }
 
305
        else
 
306
        {
 
307
            // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools 
 
308
            POINT point = {rect.left, rect.top};
 
309
            HRESULT result = getDevice()->UpdateSurface(sourceSurface, &rect, destSurface, &point);
 
310
            ASSERT(SUCCEEDED(result));
 
311
        }
 
312
    }
 
313
}
 
314
 
 
315
// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
 
316
// into the target pixel rectangle.
 
317
void Image::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum type,
 
318
                     GLint unpackAlignment, const void *input)
 
319
{
 
320
    RECT lockRect =
 
321
    {
 
322
        xoffset, yoffset,
 
323
        xoffset + width, yoffset + height
 
324
    };
 
325
 
 
326
    D3DLOCKED_RECT locked;
 
327
    HRESULT result = lock(&locked, &lockRect);
 
328
    if (FAILED(result))
 
329
    {
 
330
        return;
 
331
    }
 
332
 
 
333
    GLsizei inputPitch = ComputePitch(width, mFormat, type, unpackAlignment);
 
334
 
 
335
    switch (type)
 
336
    {
 
337
      case GL_UNSIGNED_BYTE:
 
338
        switch (mFormat)
 
339
        {
 
340
          case GL_ALPHA:
 
341
            if (supportsSSE2())
 
342
            {
 
343
                loadAlphaDataSSE2(width, height, inputPitch, input, locked.Pitch, locked.pBits);
 
344
            }
 
345
            else
 
346
            {
 
347
                loadAlphaData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
 
348
            }
 
349
            break;
 
350
          case GL_LUMINANCE:
 
351
            loadLuminanceData(width, height, inputPitch, input, locked.Pitch, locked.pBits, getD3DFormat() == D3DFMT_L8);
 
352
            break;
 
353
          case GL_LUMINANCE_ALPHA:
 
354
            loadLuminanceAlphaData(width, height, inputPitch, input, locked.Pitch, locked.pBits, getD3DFormat() == D3DFMT_A8L8);
 
355
            break;
 
356
          case GL_RGB:
 
357
            loadRGBUByteData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
 
358
            break;
 
359
          case GL_RGBA:
 
360
            if (supportsSSE2())
 
361
            {
 
362
                loadRGBAUByteDataSSE2(width, height, inputPitch, input, locked.Pitch, locked.pBits);
 
363
            }
 
364
            else
 
365
            {
 
366
                loadRGBAUByteData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
 
367
            }
 
368
            break;
 
369
          case GL_BGRA_EXT:
 
370
            loadBGRAData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
 
371
            break;
 
372
          default: UNREACHABLE();
 
373
        }
 
374
        break;
 
375
      case GL_UNSIGNED_SHORT_5_6_5:
 
376
        switch (mFormat)
 
377
        {
 
378
          case GL_RGB:
 
379
            loadRGB565Data(width, height, inputPitch, input, locked.Pitch, locked.pBits);
 
380
            break;
 
381
          default: UNREACHABLE();
 
382
        }
 
383
        break;
 
384
      case GL_UNSIGNED_SHORT_4_4_4_4:
 
385
        switch (mFormat)
 
386
        {
 
387
          case GL_RGBA:
 
388
            loadRGBA4444Data(width, height, inputPitch, input, locked.Pitch, locked.pBits);
 
389
            break;
 
390
          default: UNREACHABLE();
 
391
        }
 
392
        break;
 
393
      case GL_UNSIGNED_SHORT_5_5_5_1:
 
394
        switch (mFormat)
 
395
        {
 
396
          case GL_RGBA:
 
397
            loadRGBA5551Data(width, height, inputPitch, input, locked.Pitch, locked.pBits);
 
398
            break;
 
399
          default: UNREACHABLE();
 
400
        }
 
401
        break;
 
402
      case GL_FLOAT:
 
403
        switch (mFormat)
 
404
        {
 
405
          // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
 
406
          case GL_ALPHA:
 
407
            loadAlphaFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
 
408
            break;
 
409
          case GL_LUMINANCE:
 
410
            loadLuminanceFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
 
411
            break;
 
412
          case GL_LUMINANCE_ALPHA:
 
413
            loadLuminanceAlphaFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
 
414
            break;
 
415
          case GL_RGB:
 
416
            loadRGBFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
 
417
            break;
 
418
          case GL_RGBA:
 
419
            loadRGBAFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
 
420
            break;
 
421
          default: UNREACHABLE();
 
422
        }
 
423
        break;
 
424
      case GL_HALF_FLOAT_OES:
 
425
        switch (mFormat)
 
426
        {
 
427
          // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
 
428
          case GL_ALPHA:
 
429
            loadAlphaHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
 
430
            break;
 
431
          case GL_LUMINANCE:
 
432
            loadLuminanceHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
 
433
            break;
 
434
          case GL_LUMINANCE_ALPHA:
 
435
            loadLuminanceAlphaHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
 
436
            break;
 
437
          case GL_RGB:
 
438
            loadRGBHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
 
439
            break;
 
440
          case GL_RGBA:
 
441
            loadRGBAHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
 
442
            break;
 
443
          default: UNREACHABLE();
 
444
        }
 
445
        break;
 
446
      default: UNREACHABLE();
 
447
    }
 
448
 
 
449
    unlock();
 
450
}
 
451
 
 
452
void Image::loadAlphaData(GLsizei width, GLsizei height,
 
453
                          int inputPitch, const void *input, size_t outputPitch, void *output) const
 
454
{
 
455
    const unsigned char *source = NULL;
 
456
    unsigned char *dest = NULL;
 
457
    
 
458
    for (int y = 0; y < height; y++)
 
459
    {
 
460
        source = static_cast<const unsigned char*>(input) + y * inputPitch;
 
461
        dest = static_cast<unsigned char*>(output) + y * outputPitch;
 
462
        for (int x = 0; x < width; x++)
 
463
        {
 
464
            dest[4 * x + 0] = 0;
 
465
            dest[4 * x + 1] = 0;
 
466
            dest[4 * x + 2] = 0;
 
467
            dest[4 * x + 3] = source[x];
 
468
        }
 
469
    }
 
470
}
 
471
 
 
472
void Image::loadAlphaDataSSE2(GLsizei width, GLsizei height,
 
473
                              int inputPitch, const void *input, size_t outputPitch, void *output) const
 
474
{
 
475
    const unsigned char *source = NULL;
 
476
    unsigned int *dest = NULL;
 
477
    __m128i zeroWide = _mm_setzero_si128();
 
478
 
 
479
    for (int y = 0; y < height; y++)
 
480
    {
 
481
        source = static_cast<const unsigned char*>(input) + y * inputPitch;
 
482
        dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + y * outputPitch);
 
483
 
 
484
        int x;
 
485
        // Make output writes aligned
 
486
        for (x = 0; ((reinterpret_cast<intptr_t>(&dest[x]) & 0xF) != 0 && x < width); x++)
 
487
        {
 
488
            dest[x] = static_cast<unsigned int>(source[x]) << 24;
 
489
        }
 
490
 
 
491
        for (; x + 7 < width; x += 8)
 
492
        {
 
493
            __m128i sourceData = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(&source[x]));
 
494
            // Interleave each byte to 16bit, make the lower byte to zero
 
495
            sourceData = _mm_unpacklo_epi8(zeroWide, sourceData);
 
496
            // Interleave each 16bit to 32bit, make the lower 16bit to zero
 
497
            __m128i lo = _mm_unpacklo_epi16(zeroWide, sourceData);
 
498
            __m128i hi = _mm_unpackhi_epi16(zeroWide, sourceData);
 
499
 
 
500
            _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), lo);
 
501
            _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x + 4]), hi);
 
502
        }
 
503
 
 
504
        // Handle the remainder
 
505
        for (; x < width; x++)
 
506
        {
 
507
            dest[x] = static_cast<unsigned int>(source[x]) << 24;
 
508
        }
 
509
    }
 
510
}
 
511
 
 
512
void Image::loadAlphaFloatData(GLsizei width, GLsizei height,
 
513
                               int inputPitch, const void *input, size_t outputPitch, void *output) const
 
514
{
 
515
    const float *source = NULL;
 
516
    float *dest = NULL;
 
517
 
 
518
    for (int y = 0; y < height; y++)
 
519
    {
 
520
        source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
 
521
        dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
 
522
        for (int x = 0; x < width; x++)
 
523
        {
 
524
            dest[4 * x + 0] = 0;
 
525
            dest[4 * x + 1] = 0;
 
526
            dest[4 * x + 2] = 0;
 
527
            dest[4 * x + 3] = source[x];
 
528
        }
 
529
    }
 
530
}
 
531
 
 
532
void Image::loadAlphaHalfFloatData(GLsizei width, GLsizei height,
 
533
                                   int inputPitch, const void *input, size_t outputPitch, void *output) const
 
534
{
 
535
    const unsigned short *source = NULL;
 
536
    unsigned short *dest = NULL;
 
537
 
 
538
    for (int y = 0; y < height; y++)
 
539
    {
 
540
        source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
 
541
        dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch);
 
542
        for (int x = 0; x < width; x++)
 
543
        {
 
544
            dest[4 * x + 0] = 0;
 
545
            dest[4 * x + 1] = 0;
 
546
            dest[4 * x + 2] = 0;
 
547
            dest[4 * x + 3] = source[x];
 
548
        }
 
549
    }
 
550
}
 
551
 
 
552
void Image::loadLuminanceData(GLsizei width, GLsizei height,
 
553
                              int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
 
554
{
 
555
    const unsigned char *source = NULL;
 
556
    unsigned char *dest = NULL;
 
557
 
 
558
    for (int y = 0; y < height; y++)
 
559
    {
 
560
        source = static_cast<const unsigned char*>(input) + y * inputPitch;
 
561
        dest = static_cast<unsigned char*>(output) + y * outputPitch;
 
562
 
 
563
        if (!native)   // BGRA8 destination format
 
564
        {
 
565
            for (int x = 0; x < width; x++)
 
566
            {
 
567
                dest[4 * x + 0] = source[x];
 
568
                dest[4 * x + 1] = source[x];
 
569
                dest[4 * x + 2] = source[x];
 
570
                dest[4 * x + 3] = 0xFF;
 
571
            }
 
572
        }
 
573
        else   // L8 destination format
 
574
        {
 
575
            memcpy(dest, source, width);
 
576
        }
 
577
    }
 
578
}
 
579
 
 
580
void Image::loadLuminanceFloatData(GLsizei width, GLsizei height,
 
581
                                   int inputPitch, const void *input, size_t outputPitch, void *output) const
 
582
{
 
583
    const float *source = NULL;
 
584
    float *dest = NULL;
 
585
 
 
586
    for (int y = 0; y < height; y++)
 
587
    {
 
588
        source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
 
589
        dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
 
590
        for (int x = 0; x < width; x++)
 
591
        {
 
592
            dest[4 * x + 0] = source[x];
 
593
            dest[4 * x + 1] = source[x];
 
594
            dest[4 * x + 2] = source[x];
 
595
            dest[4 * x + 3] = 1.0f;
 
596
        }
 
597
    }
 
598
}
 
599
 
 
600
void Image::loadLuminanceHalfFloatData(GLsizei width, GLsizei height,
 
601
                                       int inputPitch, const void *input, size_t outputPitch, void *output) const
 
602
{
 
603
    const unsigned short *source = NULL;
 
604
    unsigned short *dest = NULL;
 
605
 
 
606
    for (int y = 0; y < height; y++)
 
607
    {
 
608
        source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
 
609
        dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch);
 
610
        for (int x = 0; x < width; x++)
 
611
        {
 
612
            dest[4 * x + 0] = source[x];
 
613
            dest[4 * x + 1] = source[x];
 
614
            dest[4 * x + 2] = source[x];
 
615
            dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
 
616
        }
 
617
    }
 
618
}
 
619
 
 
620
void Image::loadLuminanceAlphaData(GLsizei width, GLsizei height,
 
621
                                   int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
 
622
{
 
623
    const unsigned char *source = NULL;
 
624
    unsigned char *dest = NULL;
 
625
 
 
626
    for (int y = 0; y < height; y++)
 
627
    {
 
628
        source = static_cast<const unsigned char*>(input) + y * inputPitch;
 
629
        dest = static_cast<unsigned char*>(output) + y * outputPitch;
 
630
        
 
631
        if (!native)   // BGRA8 destination format
 
632
        {
 
633
            for (int x = 0; x < width; x++)
 
634
            {
 
635
                dest[4 * x + 0] = source[2*x+0];
 
636
                dest[4 * x + 1] = source[2*x+0];
 
637
                dest[4 * x + 2] = source[2*x+0];
 
638
                dest[4 * x + 3] = source[2*x+1];
 
639
            }
 
640
        }
 
641
        else
 
642
        {
 
643
            memcpy(dest, source, width * 2);
 
644
        }
 
645
    }
 
646
}
 
647
 
 
648
void Image::loadLuminanceAlphaFloatData(GLsizei width, GLsizei height,
 
649
                                        int inputPitch, const void *input, size_t outputPitch, void *output) const
 
650
{
 
651
    const float *source = NULL;
 
652
    float *dest = NULL;
 
653
 
 
654
    for (int y = 0; y < height; y++)
 
655
    {
 
656
        source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
 
657
        dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
 
658
        for (int x = 0; x < width; x++)
 
659
        {
 
660
            dest[4 * x + 0] = source[2*x+0];
 
661
            dest[4 * x + 1] = source[2*x+0];
 
662
            dest[4 * x + 2] = source[2*x+0];
 
663
            dest[4 * x + 3] = source[2*x+1];
 
664
        }
 
665
    }
 
666
}
 
667
 
 
668
void Image::loadLuminanceAlphaHalfFloatData(GLsizei width, GLsizei height,
 
669
                                            int inputPitch, const void *input, size_t outputPitch, void *output) const
 
670
{
 
671
    const unsigned short *source = NULL;
 
672
    unsigned short *dest = NULL;
 
673
 
 
674
    for (int y = 0; y < height; y++)
 
675
    {
 
676
        source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
 
677
        dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch);
 
678
        for (int x = 0; x < width; x++)
 
679
        {
 
680
            dest[4 * x + 0] = source[2*x+0];
 
681
            dest[4 * x + 1] = source[2*x+0];
 
682
            dest[4 * x + 2] = source[2*x+0];
 
683
            dest[4 * x + 3] = source[2*x+1];
 
684
        }
 
685
    }
 
686
}
 
687
 
 
688
void Image::loadRGBUByteData(GLsizei width, GLsizei height,
 
689
                             int inputPitch, const void *input, size_t outputPitch, void *output) const
 
690
{
 
691
    const unsigned char *source = NULL;
 
692
    unsigned char *dest = NULL;
 
693
 
 
694
    for (int y = 0; y < height; y++)
 
695
    {
 
696
        source = static_cast<const unsigned char*>(input) + y * inputPitch;
 
697
        dest = static_cast<unsigned char*>(output) + y * outputPitch;
 
698
        for (int x = 0; x < width; x++)
 
699
        {
 
700
            dest[4 * x + 0] = source[x * 3 + 2];
 
701
            dest[4 * x + 1] = source[x * 3 + 1];
 
702
            dest[4 * x + 2] = source[x * 3 + 0];
 
703
            dest[4 * x + 3] = 0xFF;
 
704
        }
 
705
    }
 
706
}
 
707
 
 
708
void Image::loadRGB565Data(GLsizei width, GLsizei height,
 
709
                           int inputPitch, const void *input, size_t outputPitch, void *output) const
 
710
{
 
711
    const unsigned short *source = NULL;
 
712
    unsigned char *dest = NULL;
 
713
 
 
714
    for (int y = 0; y < height; y++)
 
715
    {
 
716
        source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
 
717
        dest = static_cast<unsigned char*>(output) + y * outputPitch;
 
718
        for (int x = 0; x < width; x++)
 
719
        {
 
720
            unsigned short rgba = source[x];
 
721
            dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
 
722
            dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
 
723
            dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
 
724
            dest[4 * x + 3] = 0xFF;
 
725
        }
 
726
    }
 
727
}
 
728
 
 
729
void Image::loadRGBFloatData(GLsizei width, GLsizei height,
 
730
                             int inputPitch, const void *input, size_t outputPitch, void *output) const
 
731
{
 
732
    const float *source = NULL;
 
733
    float *dest = NULL;
 
734
 
 
735
    for (int y = 0; y < height; y++)
 
736
    {
 
737
        source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
 
738
        dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
 
739
        for (int x = 0; x < width; x++)
 
740
        {
 
741
            dest[4 * x + 0] = source[x * 3 + 0];
 
742
            dest[4 * x + 1] = source[x * 3 + 1];
 
743
            dest[4 * x + 2] = source[x * 3 + 2];
 
744
            dest[4 * x + 3] = 1.0f;
 
745
        }
 
746
    }
 
747
}
 
748
 
 
749
void Image::loadRGBHalfFloatData(GLsizei width, GLsizei height,
 
750
                                 int inputPitch, const void *input, size_t outputPitch, void *output) const
 
751
{
 
752
    const unsigned short *source = NULL;
 
753
    unsigned short *dest = NULL;
 
754
 
 
755
    for (int y = 0; y < height; y++)
 
756
    {
 
757
        source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
 
758
        dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch);
 
759
        for (int x = 0; x < width; x++)
 
760
        {
 
761
            dest[4 * x + 0] = source[x * 3 + 0];
 
762
            dest[4 * x + 1] = source[x * 3 + 1];
 
763
            dest[4 * x + 2] = source[x * 3 + 2];
 
764
            dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
 
765
        }
 
766
    }
 
767
}
 
768
 
 
769
void Image::loadRGBAUByteDataSSE2(GLsizei width, GLsizei height,
 
770
                                  int inputPitch, const void *input, size_t outputPitch, void *output) const
 
771
{
 
772
    const unsigned int *source = NULL;
 
773
    unsigned int *dest = NULL;
 
774
    __m128i brMask = _mm_set1_epi32(0x00ff00ff);
 
775
 
 
776
    for (int y = 0; y < height; y++)
 
777
    {
 
778
        source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
 
779
        dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + y * outputPitch);
 
780
        int x = 0;
 
781
 
 
782
        // Make output writes aligned
 
783
        for (x = 0; ((reinterpret_cast<intptr_t>(&dest[x]) & 15) != 0) && x < width; x++)
 
784
        {
 
785
            unsigned int rgba = source[x];
 
786
            dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
 
787
        }
 
788
 
 
789
        for (; x + 3 < width; x += 4)
 
790
        {
 
791
            __m128i sourceData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&source[x]));
 
792
            // Mask out g and a, which don't change
 
793
            __m128i gaComponents = _mm_andnot_si128(brMask, sourceData);
 
794
            // Mask out b and r
 
795
            __m128i brComponents = _mm_and_si128(sourceData, brMask);
 
796
            // Swap b and r
 
797
            __m128i brSwapped = _mm_shufflehi_epi16(_mm_shufflelo_epi16(brComponents, _MM_SHUFFLE(2, 3, 0, 1)), _MM_SHUFFLE(2, 3, 0, 1));
 
798
            __m128i result = _mm_or_si128(gaComponents, brSwapped);
 
799
            _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), result);
 
800
        }
 
801
 
 
802
        // Perform leftover writes
 
803
        for (; x < width; x++)
 
804
        {
 
805
            unsigned int rgba = source[x];
 
806
            dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
 
807
        }
 
808
    }
 
809
}
 
810
 
 
811
void Image::loadRGBAUByteData(GLsizei width, GLsizei height,
 
812
                              int inputPitch, const void *input, size_t outputPitch, void *output) const
 
813
{
 
814
    const unsigned int *source = NULL;
 
815
    unsigned int *dest = NULL;
 
816
    for (int y = 0; y < height; y++)
 
817
    {
 
818
        source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
 
819
        dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + y * outputPitch);
 
820
 
 
821
        for (int x = 0; x < width; x++)
 
822
        {
 
823
            unsigned int rgba = source[x];
 
824
            dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
 
825
        }
 
826
    }
 
827
}
 
828
 
 
829
void Image::loadRGBA4444Data(GLsizei width, GLsizei height,
 
830
                             int inputPitch, const void *input, size_t outputPitch, void *output) const
 
831
{
 
832
    const unsigned short *source = NULL;
 
833
    unsigned char *dest = NULL;
 
834
 
 
835
    for (int y = 0; y < height; y++)
 
836
    {
 
837
        source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
 
838
        dest = static_cast<unsigned char*>(output) + y * outputPitch;
 
839
        for (int x = 0; x < width; x++)
 
840
        {
 
841
            unsigned short rgba = source[x];
 
842
            dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
 
843
            dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
 
844
            dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
 
845
            dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
 
846
        }
 
847
    }
 
848
}
 
849
 
 
850
void Image::loadRGBA5551Data(GLsizei width, GLsizei height,
 
851
                             int inputPitch, const void *input, size_t outputPitch, void *output) const
 
852
{
 
853
    const unsigned short *source = NULL;
 
854
    unsigned char *dest = NULL;
 
855
 
 
856
    for (int y = 0; y < height; y++)
 
857
    {
 
858
        source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
 
859
        dest = static_cast<unsigned char*>(output) + y * outputPitch;
 
860
        for (int x = 0; x < width; x++)
 
861
        {
 
862
            unsigned short rgba = source[x];
 
863
            dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
 
864
            dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
 
865
            dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
 
866
            dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
 
867
        }
 
868
    }
 
869
}
 
870
 
 
871
void Image::loadRGBAFloatData(GLsizei width, GLsizei height,
 
872
                              int inputPitch, const void *input, size_t outputPitch, void *output) const
 
873
{
 
874
    const float *source = NULL;
 
875
    float *dest = NULL;
 
876
 
 
877
    for (int y = 0; y < height; y++)
 
878
    {
 
879
        source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
 
880
        dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
 
881
        memcpy(dest, source, width * 16);
 
882
    }
 
883
}
 
884
 
 
885
void Image::loadRGBAHalfFloatData(GLsizei width, GLsizei height,
 
886
                                  int inputPitch, const void *input, size_t outputPitch, void *output) const
 
887
{
 
888
    const unsigned char *source = NULL;
 
889
    unsigned char *dest = NULL;
 
890
 
 
891
    for (int y = 0; y < height; y++)
 
892
    {
 
893
        source = static_cast<const unsigned char*>(input) + y * inputPitch;
 
894
        dest = static_cast<unsigned char*>(output) + y * outputPitch;
 
895
        memcpy(dest, source, width * 8);
 
896
    }
 
897
}
 
898
 
 
899
void Image::loadBGRAData(GLsizei width, GLsizei height,
 
900
                         int inputPitch, const void *input, size_t outputPitch, void *output) const
 
901
{
 
902
    const unsigned char *source = NULL;
 
903
    unsigned char *dest = NULL;
 
904
 
 
905
    for (int y = 0; y < height; y++)
 
906
    {
 
907
        source = static_cast<const unsigned char*>(input) + y * inputPitch;
 
908
        dest = static_cast<unsigned char*>(output) + y * outputPitch;
 
909
        memcpy(dest, source, width*4);
 
910
    }
 
911
}
 
912
 
 
913
void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
 
914
                               const void *input) {
 
915
    ASSERT(xoffset % 4 == 0);
 
916
    ASSERT(yoffset % 4 == 0);
 
917
 
 
918
    RECT lockRect = {
 
919
        xoffset, yoffset,
 
920
        xoffset + width, yoffset + height
 
921
    };
 
922
 
 
923
    D3DLOCKED_RECT locked;
 
924
    HRESULT result = lock(&locked, &lockRect);
 
925
    if (FAILED(result))
 
926
    {
 
927
        return;
 
928
    }
 
929
 
 
930
    GLsizei inputSize = ComputeCompressedSize(width, height, mFormat);
 
931
    GLsizei inputPitch = ComputeCompressedPitch(width, mFormat);
 
932
    int rows = inputSize / inputPitch;
 
933
    for (int i = 0; i < rows; ++i)
 
934
    {
 
935
        memcpy((void*)((BYTE*)locked.pBits + i * locked.Pitch), (void*)((BYTE*)input + i * inputPitch), inputPitch);
 
936
    }
 
937
 
 
938
    unlock();
 
939
}
 
940
 
 
941
// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
 
942
void Image::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
 
943
{
 
944
    IDirect3DDevice9 *device = getDevice();
 
945
    IDirect3DSurface9 *renderTargetData = NULL;
 
946
    D3DSURFACE_DESC description;
 
947
    renderTarget->GetDesc(&description);
 
948
    
 
949
    HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
 
950
 
 
951
    if (FAILED(result))
 
952
    {
 
953
        ERR("Could not create matching destination surface.");
 
954
        return error(GL_OUT_OF_MEMORY);
 
955
    }
 
956
 
 
957
    result = device->GetRenderTargetData(renderTarget, renderTargetData);
 
958
 
 
959
    if (FAILED(result))
 
960
    {
 
961
        ERR("GetRenderTargetData unexpectedly failed.");
 
962
        renderTargetData->Release();
 
963
        return error(GL_OUT_OF_MEMORY);
 
964
    }
 
965
 
 
966
    RECT sourceRect = {x, y, x + width, y + height};
 
967
    RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height};
 
968
 
 
969
    if (isRenderableFormat())
 
970
    {
 
971
        result = D3DXLoadSurfaceFromSurface(getSurface(), NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0);
 
972
        
 
973
        if (FAILED(result))
 
974
        {
 
975
            ERR("Copying surfaces unexpectedly failed.");
 
976
            renderTargetData->Release();
 
977
            return error(GL_OUT_OF_MEMORY);
 
978
        }
 
979
    }
 
980
    else
 
981
    {
 
982
        D3DLOCKED_RECT sourceLock = {0};
 
983
        result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
 
984
 
 
985
        if (FAILED(result))
 
986
        {
 
987
            ERR("Failed to lock the source surface (rectangle might be invalid).");
 
988
            renderTargetData->Release();
 
989
            return error(GL_OUT_OF_MEMORY);
 
990
        }
 
991
 
 
992
        D3DLOCKED_RECT destLock = {0};
 
993
        result = lock(&destLock, &destRect);
 
994
        
 
995
        if (FAILED(result))
 
996
        {
 
997
            ERR("Failed to lock the destination surface (rectangle might be invalid).");
 
998
            renderTargetData->UnlockRect();
 
999
            renderTargetData->Release();
 
1000
            return error(GL_OUT_OF_MEMORY);
 
1001
        }
 
1002
 
 
1003
        if (destLock.pBits && sourceLock.pBits)
 
1004
        {
 
1005
            unsigned char *source = (unsigned char*)sourceLock.pBits;
 
1006
            unsigned char *dest = (unsigned char*)destLock.pBits;
 
1007
 
 
1008
            switch (description.Format)
 
1009
            {
 
1010
              case D3DFMT_X8R8G8B8:
 
1011
              case D3DFMT_A8R8G8B8:
 
1012
                switch(getD3DFormat())
 
1013
                {
 
1014
                  case D3DFMT_L8:
 
1015
                    for(int y = 0; y < height; y++)
 
1016
                    {
 
1017
                        for(int x = 0; x < width; x++)
 
1018
                        {
 
1019
                            dest[x] = source[x * 4 + 2];
 
1020
                        }
 
1021
 
 
1022
                        source += sourceLock.Pitch;
 
1023
                        dest += destLock.Pitch;
 
1024
                    }
 
1025
                    break;
 
1026
                  case D3DFMT_A8L8:
 
1027
                    for(int y = 0; y < height; y++)
 
1028
                    {
 
1029
                        for(int x = 0; x < width; x++)
 
1030
                        {
 
1031
                            dest[x * 2 + 0] = source[x * 4 + 2];
 
1032
                            dest[x * 2 + 1] = source[x * 4 + 3];
 
1033
                        }
 
1034
 
 
1035
                        source += sourceLock.Pitch;
 
1036
                        dest += destLock.Pitch;
 
1037
                    }
 
1038
                    break;
 
1039
                  default:
 
1040
                    UNREACHABLE();
 
1041
                }
 
1042
                break;
 
1043
              case D3DFMT_R5G6B5:
 
1044
                switch(getD3DFormat())
 
1045
                {
 
1046
                  case D3DFMT_L8:
 
1047
                    for(int y = 0; y < height; y++)
 
1048
                    {
 
1049
                        for(int x = 0; x < width; x++)
 
1050
                        {
 
1051
                            unsigned char red = source[x * 2 + 1] & 0xF8;
 
1052
                            dest[x] = red | (red >> 5);
 
1053
                        }
 
1054
 
 
1055
                        source += sourceLock.Pitch;
 
1056
                        dest += destLock.Pitch;
 
1057
                    }
 
1058
                    break;
 
1059
                  default:
 
1060
                    UNREACHABLE();
 
1061
                }
 
1062
                break;
 
1063
              case D3DFMT_A1R5G5B5:
 
1064
                switch(getD3DFormat())
 
1065
                {
 
1066
                  case D3DFMT_L8:
 
1067
                    for(int y = 0; y < height; y++)
 
1068
                    {
 
1069
                        for(int x = 0; x < width; x++)
 
1070
                        {
 
1071
                            unsigned char red = source[x * 2 + 1] & 0x7C;
 
1072
                            dest[x] = (red << 1) | (red >> 4);
 
1073
                        }
 
1074
 
 
1075
                        source += sourceLock.Pitch;
 
1076
                        dest += destLock.Pitch;
 
1077
                    }
 
1078
                    break;
 
1079
                  case D3DFMT_A8L8:
 
1080
                    for(int y = 0; y < height; y++)
 
1081
                    {
 
1082
                        for(int x = 0; x < width; x++)
 
1083
                        {
 
1084
                            unsigned char red = source[x * 2 + 1] & 0x7C;
 
1085
                            dest[x * 2 + 0] = (red << 1) | (red >> 4);
 
1086
                            dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
 
1087
                        }
 
1088
 
 
1089
                        source += sourceLock.Pitch;
 
1090
                        dest += destLock.Pitch;
 
1091
                    }
 
1092
                    break;
 
1093
                  default:
 
1094
                    UNREACHABLE();
 
1095
                }
 
1096
                break;
 
1097
              default:
 
1098
                UNREACHABLE();
 
1099
            }
 
1100
        }
 
1101
 
 
1102
        unlock();
 
1103
        renderTargetData->UnlockRect();
 
1104
    }
 
1105
 
 
1106
    renderTargetData->Release();
 
1107
 
 
1108
    mDirty = true;
 
1109
}
 
1110
 
 
1111
TextureStorage::TextureStorage(DWORD usage)
 
1112
    : mD3DUsage(usage),
 
1113
      mD3DPool(getDisplay()->getTexturePool(usage)),
 
1114
      mTextureSerial(issueTextureSerial())
 
1115
{
 
1116
}
 
1117
 
 
1118
TextureStorage::~TextureStorage()
 
1119
{
 
1120
}
 
1121
 
 
1122
bool TextureStorage::isRenderTarget() const
 
1123
{
 
1124
    return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0;
 
1125
}
 
1126
 
 
1127
bool TextureStorage::isManaged() const
 
1128
{
 
1129
    return (mD3DPool == D3DPOOL_MANAGED);
 
1130
}
 
1131
 
 
1132
D3DPOOL TextureStorage::getPool() const
 
1133
{
 
1134
    return mD3DPool;
 
1135
}
 
1136
 
 
1137
DWORD TextureStorage::getUsage() const
 
1138
{
 
1139
    return mD3DUsage;
 
1140
}
 
1141
 
 
1142
unsigned int TextureStorage::getTextureSerial() const
 
1143
{
 
1144
    return mTextureSerial;
 
1145
}
 
1146
 
 
1147
unsigned int TextureStorage::issueTextureSerial()
 
1148
{
 
1149
    return mCurrentTextureSerial++;
 
1150
}
 
1151
 
 
1152
Texture::Texture(GLuint id) : RefCountObject(id)
 
1153
{
 
1154
    mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
 
1155
    mMagFilter = GL_LINEAR;
 
1156
    mWrapS = GL_REPEAT;
 
1157
    mWrapT = GL_REPEAT;
 
1158
    mDirtyParameters = true;
 
1159
    mUsage = GL_NONE;
 
1160
    
 
1161
    mDirtyImages = true;
 
1162
 
 
1163
    mImmutable = false;
 
1164
}
 
1165
 
 
1166
Texture::~Texture()
 
1167
{
 
1168
}
 
1169
 
 
1170
// Returns true on successful filter state update (valid enum parameter)
 
1171
bool Texture::setMinFilter(GLenum filter)
 
1172
{
 
1173
    switch (filter)
 
1174
    {
 
1175
      case GL_NEAREST:
 
1176
      case GL_LINEAR:
 
1177
      case GL_NEAREST_MIPMAP_NEAREST:
 
1178
      case GL_LINEAR_MIPMAP_NEAREST:
 
1179
      case GL_NEAREST_MIPMAP_LINEAR:
 
1180
      case GL_LINEAR_MIPMAP_LINEAR:
 
1181
        {
 
1182
            if (mMinFilter != filter)
 
1183
            {
 
1184
                mMinFilter = filter;
 
1185
                mDirtyParameters = true;
 
1186
            }
 
1187
            return true;
 
1188
        }
 
1189
      default:
 
1190
        return false;
 
1191
    }
 
1192
}
 
1193
 
 
1194
// Returns true on successful filter state update (valid enum parameter)
 
1195
bool Texture::setMagFilter(GLenum filter)
 
1196
{
 
1197
    switch (filter)
 
1198
    {
 
1199
      case GL_NEAREST:
 
1200
      case GL_LINEAR:
 
1201
        {
 
1202
            if (mMagFilter != filter)
 
1203
            {
 
1204
                mMagFilter = filter;
 
1205
                mDirtyParameters = true;
 
1206
            }
 
1207
            return true;
 
1208
        }
 
1209
      default:
 
1210
        return false;
 
1211
    }
 
1212
}
 
1213
 
 
1214
// Returns true on successful wrap state update (valid enum parameter)
 
1215
bool Texture::setWrapS(GLenum wrap)
 
1216
{
 
1217
    switch (wrap)
 
1218
    {
 
1219
      case GL_REPEAT:
 
1220
      case GL_CLAMP_TO_EDGE:
 
1221
      case GL_MIRRORED_REPEAT:
 
1222
        {
 
1223
            if (mWrapS != wrap)
 
1224
            {
 
1225
                mWrapS = wrap;
 
1226
                mDirtyParameters = true;
 
1227
            }
 
1228
            return true;
 
1229
        }
 
1230
      default:
 
1231
        return false;
 
1232
    }
 
1233
}
 
1234
 
 
1235
// Returns true on successful wrap state update (valid enum parameter)
 
1236
bool Texture::setWrapT(GLenum wrap)
 
1237
{
 
1238
    switch (wrap)
 
1239
    {
 
1240
      case GL_REPEAT:
 
1241
      case GL_CLAMP_TO_EDGE:
 
1242
      case GL_MIRRORED_REPEAT:
 
1243
        {
 
1244
            if (mWrapT != wrap)
 
1245
            {
 
1246
                mWrapT = wrap;
 
1247
                mDirtyParameters = true;
 
1248
            }
 
1249
            return true;
 
1250
        }
 
1251
      default:
 
1252
        return false;
 
1253
    }
 
1254
}
 
1255
 
 
1256
// Returns true on successful usage state update (valid enum parameter)
 
1257
bool Texture::setUsage(GLenum usage)
 
1258
{
 
1259
    switch (usage)
 
1260
    {
 
1261
      case GL_NONE:
 
1262
      case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
 
1263
        mUsage = usage;
 
1264
        return true;
 
1265
      default:
 
1266
        return false;
 
1267
    }
 
1268
}
 
1269
 
 
1270
GLenum Texture::getMinFilter() const
 
1271
{
 
1272
    return mMinFilter;
 
1273
}
 
1274
 
 
1275
GLenum Texture::getMagFilter() const
 
1276
{
 
1277
    return mMagFilter;
 
1278
}
 
1279
 
 
1280
GLenum Texture::getWrapS() const
 
1281
{
 
1282
    return mWrapS;
 
1283
}
 
1284
 
 
1285
GLenum Texture::getWrapT() const
 
1286
{
 
1287
    return mWrapT;
 
1288
}
 
1289
 
 
1290
GLenum Texture::getUsage() const
 
1291
{
 
1292
    return mUsage;
 
1293
}
 
1294
 
 
1295
void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
 
1296
{
 
1297
    if (pixels != NULL)
 
1298
    {
 
1299
        image->loadData(0, 0, image->getWidth(), image->getHeight(), image->getType(), unpackAlignment, pixels);
 
1300
        mDirtyImages = true;
 
1301
    }
 
1302
}
 
1303
 
 
1304
void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
 
1305
{
 
1306
    if (pixels != NULL)
 
1307
    {
 
1308
        image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), pixels);
 
1309
        mDirtyImages = true;
 
1310
    }
 
1311
}
 
1312
 
 
1313
bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image)
 
1314
{
 
1315
    if (pixels != NULL)
 
1316
    {
 
1317
        image->loadData(xoffset, yoffset, width, height, type, unpackAlignment, pixels);
 
1318
        mDirtyImages = true;
 
1319
    }
 
1320
 
 
1321
    return true;
 
1322
}
 
1323
 
 
1324
bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image)
 
1325
{
 
1326
    if (pixels != NULL)
 
1327
    {
 
1328
        image->loadCompressedData(xoffset, yoffset, width, height, pixels);
 
1329
        mDirtyImages = true;
 
1330
    }
 
1331
 
 
1332
    return true;
 
1333
}
 
1334
 
 
1335
IDirect3DBaseTexture9 *Texture::getTexture()
 
1336
{
 
1337
    if (!isSamplerComplete())
 
1338
    {
 
1339
        return NULL;
 
1340
    }
 
1341
 
 
1342
    // ensure the underlying texture is created
 
1343
    if (getStorage(false) == NULL)
 
1344
    {
 
1345
        return NULL;
 
1346
    }
 
1347
 
 
1348
    updateTexture();
 
1349
 
 
1350
    return getBaseTexture();
 
1351
}
 
1352
 
 
1353
bool Texture::hasDirtyParameters() const
 
1354
{
 
1355
    return mDirtyParameters;
 
1356
}
 
1357
 
 
1358
bool Texture::hasDirtyImages() const
 
1359
{
 
1360
    return mDirtyImages;
 
1361
}
 
1362
 
 
1363
void Texture::resetDirty()
 
1364
{
 
1365
    mDirtyParameters = false;
 
1366
    mDirtyImages = false;
 
1367
}
 
1368
 
 
1369
unsigned int Texture::getTextureSerial()
 
1370
{
 
1371
    TextureStorage *texture = getStorage(false);
 
1372
    return texture ? texture->getTextureSerial() : 0;
 
1373
}
 
1374
 
 
1375
unsigned int Texture::getRenderTargetSerial(GLenum target)
 
1376
{
 
1377
    TextureStorage *texture = getStorage(true);
 
1378
    return texture ? texture->getRenderTargetSerial(target) : 0;
 
1379
}
 
1380
 
 
1381
bool Texture::isImmutable() const
 
1382
{
 
1383
    return mImmutable;
 
1384
}
 
1385
 
 
1386
GLint Texture::creationLevels(GLsizei width, GLsizei height) const
 
1387
{
 
1388
    if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture())
 
1389
    {
 
1390
        return 0;   // Maximum number of levels
 
1391
    }
 
1392
    else
 
1393
    {
 
1394
        // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
 
1395
        return 1;
 
1396
    }
 
1397
}
 
1398
 
 
1399
GLint Texture::creationLevels(GLsizei size) const
 
1400
{
 
1401
    return creationLevels(size, size);
 
1402
}
 
1403
 
 
1404
int Texture::levelCount() const
 
1405
{
 
1406
    return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
 
1407
}
 
1408
 
 
1409
Blit *Texture::getBlitter()
 
1410
{
 
1411
    Context *context = getContext();
 
1412
    return context->getBlitter();
 
1413
}
 
1414
 
 
1415
bool Texture::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged)
 
1416
{
 
1417
    if (source && dest)
 
1418
    {
 
1419
        HRESULT result;
 
1420
 
 
1421
        if (fromManaged)
 
1422
        {
 
1423
            result = D3DXLoadSurfaceFromSurface(dest, NULL, NULL, source, NULL, NULL, D3DX_FILTER_BOX, 0);
 
1424
        }
 
1425
        else
 
1426
        {
 
1427
            egl::Display *display = getDisplay();
 
1428
            IDirect3DDevice9 *device = display->getDevice();
 
1429
 
 
1430
            display->endScene();
 
1431
            result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
 
1432
        }
 
1433
 
 
1434
        if (FAILED(result))
 
1435
        {
 
1436
            ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
 
1437
            return false;
 
1438
        }
 
1439
    }
 
1440
 
 
1441
    return true;
 
1442
}
 
1443
 
 
1444
TextureStorage2D::TextureStorage2D(IDirect3DTexture9 *surfaceTexture) : TextureStorage(D3DUSAGE_RENDERTARGET), mRenderTargetSerial(RenderbufferStorage::issueSerial())
 
1445
{
 
1446
    mTexture = surfaceTexture;
 
1447
}
 
1448
 
 
1449
TextureStorage2D::TextureStorage2D(int levels, D3DFORMAT format, DWORD usage, int width, int height)
 
1450
    : TextureStorage(usage), mRenderTargetSerial(RenderbufferStorage::issueSerial())
 
1451
{
 
1452
    mTexture = NULL;
 
1453
    // if the width or height is not positive this should be treated as an incomplete texture
 
1454
    // we handle that here by skipping the d3d texture creation
 
1455
    if (width > 0 && height > 0)
 
1456
    {
 
1457
        IDirect3DDevice9 *device = getDevice();
 
1458
        HRESULT result = device->CreateTexture(width, height, levels, getUsage(), format, getPool(), &mTexture, NULL);
 
1459
 
 
1460
        if (FAILED(result))
 
1461
        {
 
1462
            ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
 
1463
            error(GL_OUT_OF_MEMORY);
 
1464
        }
 
1465
    }
 
1466
}
 
1467
 
 
1468
TextureStorage2D::~TextureStorage2D()
 
1469
{
 
1470
    if (mTexture)
 
1471
    {
 
1472
        mTexture->Release();
 
1473
    }
 
1474
}
 
1475
 
 
1476
// Increments refcount on surface.
 
1477
// caller must Release() the returned surface
 
1478
IDirect3DSurface9 *TextureStorage2D::getSurfaceLevel(int level)
 
1479
{
 
1480
    IDirect3DSurface9 *surface = NULL;
 
1481
 
 
1482
    if (mTexture)
 
1483
    {
 
1484
        HRESULT result = mTexture->GetSurfaceLevel(level, &surface);
 
1485
        ASSERT(SUCCEEDED(result));
 
1486
    }
 
1487
 
 
1488
    return surface;
 
1489
}
 
1490
 
 
1491
IDirect3DBaseTexture9 *TextureStorage2D::getBaseTexture() const
 
1492
{
 
1493
    return mTexture;
 
1494
}
 
1495
 
 
1496
unsigned int TextureStorage2D::getRenderTargetSerial(GLenum target) const
 
1497
{
 
1498
    return mRenderTargetSerial;
 
1499
}
 
1500
 
 
1501
Texture2D::Texture2D(GLuint id) : Texture(id)
 
1502
{
 
1503
    mTexStorage = NULL;
 
1504
    mSurface = NULL;
 
1505
    mColorbufferProxy = NULL;
 
1506
    mProxyRefs = 0;
 
1507
}
 
1508
 
 
1509
Texture2D::~Texture2D()
 
1510
{
 
1511
    mColorbufferProxy = NULL;
 
1512
 
 
1513
    delete mTexStorage;
 
1514
    mTexStorage = NULL;
 
1515
    
 
1516
    if (mSurface)
 
1517
    {
 
1518
        mSurface->setBoundTexture(NULL);
 
1519
        mSurface = NULL;
 
1520
    }
 
1521
}
 
1522
 
 
1523
// We need to maintain a count of references to renderbuffers acting as 
 
1524
// proxies for this texture, so that we do not attempt to use a pointer 
 
1525
// to a renderbuffer proxy which has been deleted.
 
1526
void Texture2D::addProxyRef(const Renderbuffer *proxy)
 
1527
{
 
1528
    mProxyRefs++;
 
1529
}
 
1530
 
 
1531
void Texture2D::releaseProxy(const Renderbuffer *proxy)
 
1532
{
 
1533
    if (mProxyRefs > 0)
 
1534
        mProxyRefs--;
 
1535
 
 
1536
    if (mProxyRefs == 0)
 
1537
        mColorbufferProxy = NULL;
 
1538
}
 
1539
 
 
1540
GLenum Texture2D::getTarget() const
 
1541
{
 
1542
    return GL_TEXTURE_2D;
 
1543
}
 
1544
 
 
1545
GLsizei Texture2D::getWidth(GLint level) const
 
1546
{
 
1547
    if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
 
1548
        return mImageArray[level].getWidth();
 
1549
    else
 
1550
        return 0;
 
1551
}
 
1552
 
 
1553
GLsizei Texture2D::getHeight(GLint level) const
 
1554
{
 
1555
    if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
 
1556
        return mImageArray[level].getHeight();
 
1557
    else
 
1558
        return 0;
 
1559
}
 
1560
 
 
1561
GLenum Texture2D::getInternalFormat(GLint level) const
 
1562
{
 
1563
    if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
 
1564
        return mImageArray[level].getFormat();
 
1565
    else
 
1566
        return GL_NONE;
 
1567
}
 
1568
 
 
1569
D3DFORMAT Texture2D::getD3DFormat(GLint level) const
 
1570
{
 
1571
    if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
 
1572
        return mImageArray[level].getD3DFormat();
 
1573
    else
 
1574
        return D3DFMT_UNKNOWN;
 
1575
}
 
1576
 
 
1577
void Texture2D::redefineImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
 
1578
{
 
1579
    releaseTexImage();
 
1580
 
 
1581
    bool redefined = mImageArray[level].redefine(format, width, height, type, false);
 
1582
 
 
1583
    if (mTexStorage && redefined)
 
1584
    {
 
1585
        for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
 
1586
        {
 
1587
            mImageArray[i].markDirty();
 
1588
        }
 
1589
 
 
1590
        delete mTexStorage;
 
1591
        mTexStorage = NULL;
 
1592
        mDirtyImages = true;
 
1593
    }
 
1594
}
 
1595
 
 
1596
void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 
1597
{
 
1598
    redefineImage(level, format, width, height, type);
 
1599
 
 
1600
    Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
 
1601
}
 
1602
 
 
1603
void Texture2D::bindTexImage(egl::Surface *surface)
 
1604
{
 
1605
    releaseTexImage();
 
1606
 
 
1607
    GLenum format;
 
1608
 
 
1609
    switch(surface->getFormat())
 
1610
    {
 
1611
      case D3DFMT_A8R8G8B8:
 
1612
        format = GL_RGBA;
 
1613
        break;
 
1614
      case D3DFMT_X8R8G8B8:
 
1615
        format = GL_RGB;
 
1616
        break;
 
1617
      default:
 
1618
        UNIMPLEMENTED();
 
1619
        return;
 
1620
    }
 
1621
 
 
1622
    mImageArray[0].redefine(format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE, true);
 
1623
 
 
1624
    delete mTexStorage;
 
1625
    mTexStorage = new TextureStorage2D(surface->getOffscreenTexture());
 
1626
 
 
1627
    mDirtyImages = true;
 
1628
    mSurface = surface;
 
1629
    mSurface->setBoundTexture(this);
 
1630
}
 
1631
 
 
1632
void Texture2D::releaseTexImage()
 
1633
{
 
1634
    if (mSurface)
 
1635
    {
 
1636
        mSurface->setBoundTexture(NULL);
 
1637
        mSurface = NULL;
 
1638
 
 
1639
        if (mTexStorage)
 
1640
        {
 
1641
            delete mTexStorage;
 
1642
            mTexStorage = NULL;
 
1643
        }
 
1644
 
 
1645
        for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
 
1646
        {
 
1647
            mImageArray[i].redefine(GL_RGBA, 0, 0, GL_UNSIGNED_BYTE, true);
 
1648
        }
 
1649
    }
 
1650
}
 
1651
 
 
1652
void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
 
1653
{
 
1654
    redefineImage(level, format, width, height, GL_UNSIGNED_BYTE);
 
1655
 
 
1656
    Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
 
1657
}
 
1658
 
 
1659
void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
 
1660
{
 
1661
    ASSERT(mImageArray[level].getSurface() != NULL);
 
1662
 
 
1663
    if (level < levelCount())
 
1664
    {
 
1665
        IDirect3DSurface9 *destLevel = mTexStorage->getSurfaceLevel(level);
 
1666
 
 
1667
        if (destLevel)
 
1668
        {
 
1669
            Image *image = &mImageArray[level];
 
1670
            image->updateSurface(destLevel, xoffset, yoffset, width, height);
 
1671
 
 
1672
            destLevel->Release();
 
1673
            image->markClean();
 
1674
        }
 
1675
    }
 
1676
}
 
1677
 
 
1678
void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 
1679
{
 
1680
    if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
 
1681
    {
 
1682
        commitRect(level, xoffset, yoffset, width, height);
 
1683
    }
 
1684
}
 
1685
 
 
1686
void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
 
1687
{
 
1688
    if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
 
1689
    {
 
1690
        commitRect(level, xoffset, yoffset, width, height);
 
1691
    }
 
1692
}
 
1693
 
 
1694
void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
 
1695
{
 
1696
    IDirect3DSurface9 *renderTarget = source->getRenderTarget();
 
1697
 
 
1698
    if (!renderTarget)
 
1699
    {
 
1700
        ERR("Failed to retrieve the render target.");
 
1701
        return error(GL_OUT_OF_MEMORY);
 
1702
    }
 
1703
 
 
1704
    redefineImage(level, format, width, height, GL_UNSIGNED_BYTE);
 
1705
   
 
1706
    if (!mImageArray[level].isRenderableFormat())
 
1707
    {
 
1708
        mImageArray[level].copy(0, 0, x, y, width, height, renderTarget);
 
1709
        mDirtyImages = true;
 
1710
    }
 
1711
    else
 
1712
    {
 
1713
        if (!mTexStorage || !mTexStorage->isRenderTarget())
 
1714
        {
 
1715
            convertToRenderTarget();
 
1716
        }
 
1717
        
 
1718
        mImageArray[level].markClean();
 
1719
 
 
1720
        if (width != 0 && height != 0 && level < levelCount())
 
1721
        {
 
1722
            RECT sourceRect;
 
1723
            sourceRect.left = x;
 
1724
            sourceRect.right = x + width;
 
1725
            sourceRect.top = y;
 
1726
            sourceRect.bottom = y + height;
 
1727
            
 
1728
            IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level);
 
1729
 
 
1730
            if (dest)
 
1731
            {
 
1732
                getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest);
 
1733
                dest->Release();
 
1734
            }
 
1735
        }
 
1736
    }
 
1737
 
 
1738
    renderTarget->Release();
 
1739
}
 
1740
 
 
1741
void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
 
1742
{
 
1743
    if (xoffset + width > mImageArray[level].getWidth() || yoffset + height > mImageArray[level].getHeight())
 
1744
    {
 
1745
        return error(GL_INVALID_VALUE);
 
1746
    }
 
1747
 
 
1748
    IDirect3DSurface9 *renderTarget = source->getRenderTarget();
 
1749
 
 
1750
    if (!renderTarget)
 
1751
    {
 
1752
        ERR("Failed to retrieve the render target.");
 
1753
        return error(GL_OUT_OF_MEMORY);
 
1754
    }
 
1755
 
 
1756
    if (!mImageArray[level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
 
1757
    {
 
1758
        mImageArray[level].copy(xoffset, yoffset, x, y, width, height, renderTarget);
 
1759
        mDirtyImages = true;
 
1760
    }
 
1761
    else
 
1762
    {
 
1763
        if (!mTexStorage || !mTexStorage->isRenderTarget())
 
1764
        {
 
1765
            convertToRenderTarget();
 
1766
        }
 
1767
        
 
1768
        updateTexture();
 
1769
 
 
1770
        if (level < levelCount())
 
1771
        {
 
1772
            RECT sourceRect;
 
1773
            sourceRect.left = x;
 
1774
            sourceRect.right = x + width;
 
1775
            sourceRect.top = y;
 
1776
            sourceRect.bottom = y + height;
 
1777
 
 
1778
 
 
1779
            IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level);
 
1780
 
 
1781
            if (dest)
 
1782
            {
 
1783
                getBlitter()->copy(renderTarget, sourceRect, mImageArray[0].getFormat(), xoffset, yoffset, dest);
 
1784
                dest->Release();
 
1785
            }
 
1786
        }
 
1787
    }
 
1788
 
 
1789
    renderTarget->Release();
 
1790
}
 
1791
 
 
1792
void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
 
1793
{
 
1794
    GLenum format = gl::ExtractFormat(internalformat);
 
1795
    GLenum type = gl::ExtractType(internalformat);
 
1796
    D3DFORMAT d3dfmt = ConvertTextureFormatType(format, type);
 
1797
    DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false);
 
1798
 
 
1799
    delete mTexStorage;
 
1800
    mTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height);
 
1801
    mImmutable = true;
 
1802
 
 
1803
    for (int level = 0; level < levels; level++)
 
1804
    {
 
1805
        mImageArray[level].redefine(format, width, height, type, true);
 
1806
        width = std::max(1, width >> 1);
 
1807
        height = std::max(1, height >> 1);
 
1808
    }
 
1809
 
 
1810
    for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
 
1811
    {
 
1812
        mImageArray[level].redefine(GL_NONE, 0, 0, GL_UNSIGNED_BYTE, true);
 
1813
    }
 
1814
 
 
1815
    if (mTexStorage->isManaged())
 
1816
    {
 
1817
        int levels = levelCount();
 
1818
 
 
1819
        for (int level = 0; level < levels; level++)
 
1820
        {
 
1821
            IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level);
 
1822
            mImageArray[level].setManagedSurface(surface);
 
1823
        }
 
1824
    }
 
1825
}
 
1826
 
 
1827
// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
 
1828
bool Texture2D::isSamplerComplete() const
 
1829
{
 
1830
    GLsizei width = mImageArray[0].getWidth();
 
1831
    GLsizei height = mImageArray[0].getHeight();
 
1832
 
 
1833
    if (width <= 0 || height <= 0)
 
1834
    {
 
1835
        return false;
 
1836
    }
 
1837
 
 
1838
    bool mipmapping = false;
 
1839
 
 
1840
    switch (mMinFilter)
 
1841
    {
 
1842
      case GL_NEAREST:
 
1843
      case GL_LINEAR:
 
1844
        mipmapping = false;
 
1845
        break;
 
1846
      case GL_NEAREST_MIPMAP_NEAREST:
 
1847
      case GL_LINEAR_MIPMAP_NEAREST:
 
1848
      case GL_NEAREST_MIPMAP_LINEAR:
 
1849
      case GL_LINEAR_MIPMAP_LINEAR:
 
1850
        mipmapping = true;
 
1851
        break;
 
1852
      default: UNREACHABLE();
 
1853
    }
 
1854
 
 
1855
    if ((getInternalFormat(0) == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) ||
 
1856
        (getInternalFormat(0) == GL_HALF_FLOAT_OES && !getContext()->supportsFloat16LinearFilter()))
 
1857
    {
 
1858
        if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
 
1859
        {
 
1860
            return false;
 
1861
        }
 
1862
    }
 
1863
 
 
1864
    bool npotSupport = getContext()->supportsNonPower2Texture();
 
1865
 
 
1866
    if (!npotSupport)
 
1867
    {
 
1868
        if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
 
1869
            (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
 
1870
        {
 
1871
            return false;
 
1872
        }
 
1873
    }
 
1874
 
 
1875
    if (mipmapping)
 
1876
    {
 
1877
        if (!npotSupport)
 
1878
        {
 
1879
            if (!isPow2(width) || !isPow2(height))
 
1880
            {
 
1881
                return false;
 
1882
            }
 
1883
        }
 
1884
 
 
1885
        if (!isMipmapComplete())
 
1886
        {
 
1887
            return false;
 
1888
        }
 
1889
    }
 
1890
 
 
1891
    return true;
 
1892
}
 
1893
 
 
1894
// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
 
1895
bool Texture2D::isMipmapComplete() const
 
1896
{
 
1897
    if (isImmutable())
 
1898
    {
 
1899
        return true;
 
1900
    }
 
1901
 
 
1902
    GLsizei width = mImageArray[0].getWidth();
 
1903
    GLsizei height = mImageArray[0].getHeight();
 
1904
 
 
1905
    if (width <= 0 || height <= 0)
 
1906
    {
 
1907
        return false;
 
1908
    }
 
1909
 
 
1910
    int q = log2(std::max(width, height));
 
1911
 
 
1912
    for (int level = 1; level <= q; level++)
 
1913
    {
 
1914
        if (mImageArray[level].getFormat() != mImageArray[0].getFormat())
 
1915
        {
 
1916
            return false;
 
1917
        }
 
1918
 
 
1919
        if (mImageArray[level].getType() != mImageArray[0].getType())
 
1920
        {
 
1921
            return false;
 
1922
        }
 
1923
 
 
1924
        if (mImageArray[level].getWidth() != std::max(1, width >> level))
 
1925
        {
 
1926
            return false;
 
1927
        }
 
1928
 
 
1929
        if (mImageArray[level].getHeight() != std::max(1, height >> level))
 
1930
        {
 
1931
            return false;
 
1932
        }
 
1933
    }
 
1934
 
 
1935
    return true;
 
1936
}
 
1937
 
 
1938
bool Texture2D::isCompressed(GLint level) const
 
1939
{
 
1940
    return IsCompressed(getInternalFormat(level));
 
1941
}
 
1942
 
 
1943
bool Texture2D::isDepth(GLint level) const
 
1944
{
 
1945
    return IsDepthTexture(getInternalFormat(level));
 
1946
}
 
1947
 
 
1948
IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
 
1949
{
 
1950
    return mTexStorage ? mTexStorage->getBaseTexture() : NULL;
 
1951
}
 
1952
 
 
1953
// Constructs a Direct3D 9 texture resource from the texture images
 
1954
void Texture2D::createTexture()
 
1955
{
 
1956
    GLsizei width = mImageArray[0].getWidth();
 
1957
    GLsizei height = mImageArray[0].getHeight();
 
1958
    GLint levels = creationLevels(width, height);
 
1959
    D3DFORMAT d3dfmt = mImageArray[0].getD3DFormat();
 
1960
    DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false);
 
1961
 
 
1962
    delete mTexStorage;
 
1963
    mTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height);
 
1964
    
 
1965
    if (mTexStorage->isManaged())
 
1966
    {
 
1967
        int levels = levelCount();
 
1968
 
 
1969
        for (int level = 0; level < levels; level++)
 
1970
        {
 
1971
            IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level);
 
1972
            mImageArray[level].setManagedSurface(surface);
 
1973
        }
 
1974
    }
 
1975
 
 
1976
    mDirtyImages = true;
 
1977
}
 
1978
 
 
1979
void Texture2D::updateTexture()
 
1980
{
 
1981
    int levels = levelCount();
 
1982
 
 
1983
    for (int level = 0; level < levels; level++)
 
1984
    {
 
1985
        Image *image = &mImageArray[level];
 
1986
 
 
1987
        if (image->isDirty())
 
1988
        {
 
1989
            commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight());
 
1990
        }
 
1991
    }
 
1992
}
 
1993
 
 
1994
void Texture2D::convertToRenderTarget()
 
1995
{
 
1996
    TextureStorage2D *newTexStorage = NULL;
 
1997
 
 
1998
    if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0)
 
1999
    {
 
2000
        GLsizei width = mImageArray[0].getWidth();
 
2001
        GLsizei height = mImageArray[0].getHeight();
 
2002
        GLint levels = creationLevels(width, height);
 
2003
        D3DFORMAT d3dfmt = mImageArray[0].getD3DFormat();
 
2004
        DWORD d3dusage = GetTextureUsage(d3dfmt, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true);
 
2005
 
 
2006
        newTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height);
 
2007
 
 
2008
        if (mTexStorage != NULL)
 
2009
        {
 
2010
            int levels = levelCount();
 
2011
            for (int i = 0; i < levels; i++)
 
2012
            {
 
2013
                IDirect3DSurface9 *source = mTexStorage->getSurfaceLevel(i);
 
2014
                IDirect3DSurface9 *dest = newTexStorage->getSurfaceLevel(i);
 
2015
 
 
2016
                if (!copyToRenderTarget(dest, source, mTexStorage->isManaged()))
 
2017
                {   
 
2018
                   delete newTexStorage;
 
2019
                   if (source) source->Release();
 
2020
                   if (dest) dest->Release();
 
2021
                   return error(GL_OUT_OF_MEMORY);
 
2022
                }
 
2023
 
 
2024
                if (source) source->Release();
 
2025
                if (dest) dest->Release();
 
2026
            }
 
2027
        }
 
2028
    }
 
2029
 
 
2030
    delete mTexStorage;
 
2031
    mTexStorage = newTexStorage;
 
2032
 
 
2033
    mDirtyImages = true;
 
2034
}
 
2035
 
 
2036
void Texture2D::generateMipmaps()
 
2037
{
 
2038
    if (!getContext()->supportsNonPower2Texture())
 
2039
    {
 
2040
        if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight()))
 
2041
        {
 
2042
            return error(GL_INVALID_OPERATION);
 
2043
        }
 
2044
    }
 
2045
 
 
2046
    // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
 
2047
    unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight()));
 
2048
    for (unsigned int i = 1; i <= q; i++)
 
2049
    {
 
2050
        redefineImage(i, mImageArray[0].getFormat(), 
 
2051
                         std::max(mImageArray[0].getWidth() >> i, 1),
 
2052
                         std::max(mImageArray[0].getHeight() >> i, 1),
 
2053
                         mImageArray[0].getType());
 
2054
    }
 
2055
 
 
2056
    if (mTexStorage && mTexStorage->isRenderTarget())
 
2057
    {
 
2058
        for (unsigned int i = 1; i <= q; i++)
 
2059
        {
 
2060
            IDirect3DSurface9 *upper = mTexStorage->getSurfaceLevel(i - 1);
 
2061
            IDirect3DSurface9 *lower = mTexStorage->getSurfaceLevel(i);
 
2062
 
 
2063
            if (upper != NULL && lower != NULL)
 
2064
            {
 
2065
                getBlitter()->boxFilter(upper, lower);
 
2066
            }
 
2067
 
 
2068
            if (upper != NULL) upper->Release();
 
2069
            if (lower != NULL) lower->Release();
 
2070
 
 
2071
            mImageArray[i].markClean();
 
2072
        }
 
2073
    }
 
2074
    else
 
2075
    {
 
2076
        for (unsigned int i = 1; i <= q; i++)
 
2077
        {
 
2078
            if (mImageArray[i].getSurface() == NULL)
 
2079
            {
 
2080
                return error(GL_OUT_OF_MEMORY);
 
2081
            }
 
2082
 
 
2083
            if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].getSurface(), NULL, NULL, mImageArray[i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0)))
 
2084
            {
 
2085
                ERR(" failed to load filter %d to %d.", i - 1, i);
 
2086
            }
 
2087
 
 
2088
            mImageArray[i].markDirty();
 
2089
        }
 
2090
    }
 
2091
}
 
2092
 
 
2093
Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
 
2094
{
 
2095
    if (target != GL_TEXTURE_2D)
 
2096
    {
 
2097
        return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
 
2098
    }
 
2099
 
 
2100
    if (mColorbufferProxy == NULL)
 
2101
    {
 
2102
        mColorbufferProxy = new Renderbuffer(id(), new RenderbufferTexture2D(this, target));
 
2103
    }
 
2104
 
 
2105
    return mColorbufferProxy;
 
2106
}
 
2107
 
 
2108
// Increments refcount on surface.
 
2109
// caller must Release() the returned surface
 
2110
IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
 
2111
{
 
2112
    ASSERT(target == GL_TEXTURE_2D);
 
2113
 
 
2114
    // ensure the underlying texture is created
 
2115
    if (getStorage(true) == NULL)
 
2116
    {
 
2117
        return NULL;
 
2118
    }
 
2119
 
 
2120
    updateTexture();
 
2121
    
 
2122
    // ensure this is NOT a depth texture
 
2123
    if (isDepth(0))
 
2124
    {
 
2125
        return NULL;
 
2126
    }
 
2127
    return mTexStorage->getSurfaceLevel(0);
 
2128
}
 
2129
 
 
2130
// Increments refcount on surface.
 
2131
// caller must Release() the returned surface
 
2132
IDirect3DSurface9 *Texture2D::getDepthStencil(GLenum target)
 
2133
{
 
2134
    ASSERT(target == GL_TEXTURE_2D);
 
2135
 
 
2136
    // ensure the underlying texture is created
 
2137
    if (getStorage(true) == NULL)
 
2138
    {
 
2139
        return NULL;
 
2140
    }
 
2141
 
 
2142
    updateTexture();
 
2143
 
 
2144
    // ensure this is actually a depth texture
 
2145
    if (!isDepth(0))
 
2146
    {
 
2147
        return NULL;
 
2148
    }
 
2149
    return mTexStorage->getSurfaceLevel(0);
 
2150
}
 
2151
 
 
2152
TextureStorage *Texture2D::getStorage(bool renderTarget)
 
2153
{
 
2154
    if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
 
2155
    {
 
2156
        if (renderTarget)
 
2157
        {
 
2158
            convertToRenderTarget();
 
2159
        }
 
2160
        else
 
2161
        {
 
2162
            createTexture();
 
2163
        }
 
2164
    }
 
2165
 
 
2166
    return mTexStorage;
 
2167
}
 
2168
 
 
2169
TextureStorageCubeMap::TextureStorageCubeMap(int levels, D3DFORMAT format, DWORD usage, int size)
 
2170
    : TextureStorage(usage), mFirstRenderTargetSerial(RenderbufferStorage::issueCubeSerials())
 
2171
{
 
2172
    mTexture = NULL;
 
2173
    // if the size is not positive this should be treated as an incomplete texture
 
2174
    // we handle that here by skipping the d3d texture creation
 
2175
    if (size > 0)
 
2176
    {
 
2177
        IDirect3DDevice9 *device = getDevice();
 
2178
        HRESULT result = device->CreateCubeTexture(size, levels, getUsage(), format, getPool(), &mTexture, NULL);
 
2179
 
 
2180
        if (FAILED(result))
 
2181
        {
 
2182
            ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
 
2183
            error(GL_OUT_OF_MEMORY);
 
2184
        }
 
2185
    }
 
2186
}
 
2187
 
 
2188
TextureStorageCubeMap::~TextureStorageCubeMap()
 
2189
{
 
2190
    if (mTexture)
 
2191
    {
 
2192
        mTexture->Release();
 
2193
    }
 
2194
}
 
2195
 
 
2196
// Increments refcount on surface.
 
2197
// caller must Release() the returned surface
 
2198
IDirect3DSurface9 *TextureStorageCubeMap::getCubeMapSurface(GLenum faceTarget, int level)
 
2199
{
 
2200
    IDirect3DSurface9 *surface = NULL;
 
2201
 
 
2202
    if (mTexture)
 
2203
    {
 
2204
        HRESULT result = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(faceTarget), level, &surface);
 
2205
        ASSERT(SUCCEEDED(result));
 
2206
    }
 
2207
 
 
2208
    return surface;
 
2209
}
 
2210
 
 
2211
IDirect3DBaseTexture9 *TextureStorageCubeMap::getBaseTexture() const
 
2212
{
 
2213
    return mTexture;
 
2214
}
 
2215
 
 
2216
unsigned int TextureStorageCubeMap::getRenderTargetSerial(GLenum target) const
 
2217
{
 
2218
    return mFirstRenderTargetSerial + TextureCubeMap::faceIndex(target);
 
2219
}
 
2220
 
 
2221
TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
 
2222
{
 
2223
    mTexStorage = NULL;
 
2224
    for (int i = 0; i < 6; i++)
 
2225
    {
 
2226
        mFaceProxies[i] = NULL;
 
2227
        mFaceProxyRefs[i] = 0;
 
2228
    }
 
2229
}
 
2230
 
 
2231
TextureCubeMap::~TextureCubeMap()
 
2232
{
 
2233
    for (int i = 0; i < 6; i++)
 
2234
    {
 
2235
        mFaceProxies[i] = NULL;
 
2236
    }
 
2237
 
 
2238
    delete mTexStorage;
 
2239
    mTexStorage = NULL;
 
2240
}
 
2241
 
 
2242
// We need to maintain a count of references to renderbuffers acting as 
 
2243
// proxies for this texture, so that the texture is not deleted while 
 
2244
// proxy references still exist. If the reference count drops to zero,
 
2245
// we set our proxy pointer NULL, so that a new attempt at referencing
 
2246
// will cause recreation.
 
2247
void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
 
2248
{
 
2249
    for (int i = 0; i < 6; i++)
 
2250
    {
 
2251
        if (mFaceProxies[i] == proxy)
 
2252
            mFaceProxyRefs[i]++;
 
2253
    }
 
2254
}
 
2255
 
 
2256
void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
 
2257
{
 
2258
    for (int i = 0; i < 6; i++)
 
2259
    {
 
2260
        if (mFaceProxies[i] == proxy)
 
2261
        {
 
2262
            if (mFaceProxyRefs[i] > 0)
 
2263
                mFaceProxyRefs[i]--;
 
2264
 
 
2265
            if (mFaceProxyRefs[i] == 0)
 
2266
                mFaceProxies[i] = NULL;
 
2267
        }
 
2268
    }
 
2269
}
 
2270
 
 
2271
GLenum TextureCubeMap::getTarget() const
 
2272
{
 
2273
    return GL_TEXTURE_CUBE_MAP;
 
2274
}
 
2275
 
 
2276
GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
 
2277
{
 
2278
    if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
 
2279
        return mImageArray[faceIndex(target)][level].getWidth();
 
2280
    else
 
2281
        return 0;
 
2282
}
 
2283
 
 
2284
GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
 
2285
{
 
2286
    if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
 
2287
        return mImageArray[faceIndex(target)][level].getHeight();
 
2288
    else
 
2289
        return 0;
 
2290
}
 
2291
 
 
2292
GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
 
2293
{
 
2294
    if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
 
2295
        return mImageArray[faceIndex(target)][level].getFormat();
 
2296
    else
 
2297
        return GL_NONE;
 
2298
}
 
2299
 
 
2300
D3DFORMAT TextureCubeMap::getD3DFormat(GLenum target, GLint level) const
 
2301
{
 
2302
    if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
 
2303
        return mImageArray[faceIndex(target)][level].getD3DFormat();
 
2304
    else
 
2305
        return D3DFMT_UNKNOWN;
 
2306
}
 
2307
 
 
2308
void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 
2309
{
 
2310
    setImage(0, level, width, height, format, type, unpackAlignment, pixels);
 
2311
}
 
2312
 
 
2313
void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 
2314
{
 
2315
    setImage(1, level, width, height, format, type, unpackAlignment, pixels);
 
2316
}
 
2317
 
 
2318
void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 
2319
{
 
2320
    setImage(2, level, width, height, format, type, unpackAlignment, pixels);
 
2321
}
 
2322
 
 
2323
void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 
2324
{
 
2325
    setImage(3, level, width, height, format, type, unpackAlignment, pixels);
 
2326
}
 
2327
 
 
2328
void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 
2329
{
 
2330
    setImage(4, level, width, height, format, type, unpackAlignment, pixels);
 
2331
}
 
2332
 
 
2333
void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 
2334
{
 
2335
    setImage(5, level, width, height, format, type, unpackAlignment, pixels);
 
2336
}
 
2337
 
 
2338
void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
 
2339
{
 
2340
    redefineImage(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
 
2341
 
 
2342
    Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
 
2343
}
 
2344
 
 
2345
void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
 
2346
{
 
2347
    ASSERT(mImageArray[face][level].getSurface() != NULL);
 
2348
 
 
2349
    if (level < levelCount())
 
2350
    {
 
2351
        IDirect3DSurface9 *destLevel = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
 
2352
        ASSERT(destLevel != NULL);
 
2353
 
 
2354
        if (destLevel != NULL)
 
2355
        {
 
2356
            Image *image = &mImageArray[face][level];
 
2357
            image->updateSurface(destLevel, xoffset, yoffset, width, height);
 
2358
 
 
2359
            destLevel->Release();
 
2360
            image->markClean();
 
2361
        }
 
2362
    }
 
2363
}
 
2364
 
 
2365
void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 
2366
{
 
2367
    if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
 
2368
    {
 
2369
        commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
 
2370
    }
 
2371
}
 
2372
 
 
2373
void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
 
2374
{
 
2375
    if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
 
2376
    {
 
2377
        commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
 
2378
    }
 
2379
}
 
2380
 
 
2381
// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
 
2382
bool TextureCubeMap::isSamplerComplete() const
 
2383
{
 
2384
    int size = mImageArray[0][0].getWidth();
 
2385
 
 
2386
    bool mipmapping;
 
2387
 
 
2388
    switch (mMinFilter)
 
2389
    {
 
2390
      case GL_NEAREST:
 
2391
      case GL_LINEAR:
 
2392
        mipmapping = false;
 
2393
        break;
 
2394
      case GL_NEAREST_MIPMAP_NEAREST:
 
2395
      case GL_LINEAR_MIPMAP_NEAREST:
 
2396
      case GL_NEAREST_MIPMAP_LINEAR:
 
2397
      case GL_LINEAR_MIPMAP_LINEAR:
 
2398
        mipmapping = true;
 
2399
        break;
 
2400
      default:
 
2401
        UNREACHABLE();
 
2402
        return false;
 
2403
    }
 
2404
 
 
2405
    if ((getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) ||
 
2406
        (getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES && !getContext()->supportsFloat16LinearFilter()))
 
2407
    {
 
2408
        if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
 
2409
        {
 
2410
            return false;
 
2411
        }
 
2412
    }
 
2413
 
 
2414
    if (!isPow2(size) && !getContext()->supportsNonPower2Texture())
 
2415
    {
 
2416
        if (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE || mipmapping)
 
2417
        {
 
2418
            return false;
 
2419
        }
 
2420
    }
 
2421
 
 
2422
    if (!mipmapping)
 
2423
    {
 
2424
        if (!isCubeComplete())
 
2425
        {
 
2426
            return false;
 
2427
        }
 
2428
    }
 
2429
    else
 
2430
    {
 
2431
        if (!isMipmapCubeComplete())   // Also tests for isCubeComplete()
 
2432
        {
 
2433
            return false;
 
2434
        }
 
2435
    }
 
2436
 
 
2437
    return true;
 
2438
}
 
2439
 
 
2440
// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
 
2441
bool TextureCubeMap::isCubeComplete() const
 
2442
{
 
2443
    if (mImageArray[0][0].getWidth() <= 0 || mImageArray[0][0].getHeight() != mImageArray[0][0].getWidth())
 
2444
    {
 
2445
        return false;
 
2446
    }
 
2447
 
 
2448
    for (unsigned int face = 1; face < 6; face++)
 
2449
    {
 
2450
        if (mImageArray[face][0].getWidth() != mImageArray[0][0].getWidth() ||
 
2451
            mImageArray[face][0].getWidth() != mImageArray[0][0].getHeight() ||
 
2452
            mImageArray[face][0].getFormat() != mImageArray[0][0].getFormat() ||
 
2453
            mImageArray[face][0].getType() != mImageArray[0][0].getType())
 
2454
        {
 
2455
            return false;
 
2456
        }
 
2457
    }
 
2458
 
 
2459
    return true;
 
2460
}
 
2461
 
 
2462
bool TextureCubeMap::isMipmapCubeComplete() const
 
2463
{
 
2464
    if (isImmutable())
 
2465
    {
 
2466
        return true;
 
2467
    }
 
2468
 
 
2469
    if (!isCubeComplete())
 
2470
    {
 
2471
        return false;
 
2472
    }
 
2473
 
 
2474
    GLsizei size = mImageArray[0][0].getWidth();
 
2475
 
 
2476
    int q = log2(size);
 
2477
 
 
2478
    for (int face = 0; face < 6; face++)
 
2479
    {
 
2480
        for (int level = 1; level <= q; level++)
 
2481
        {
 
2482
            if (mImageArray[face][level].getFormat() != mImageArray[0][0].getFormat())
 
2483
            {
 
2484
                return false;
 
2485
            }
 
2486
 
 
2487
            if (mImageArray[face][level].getType() != mImageArray[0][0].getType())
 
2488
            {
 
2489
                return false;
 
2490
            }
 
2491
 
 
2492
            if (mImageArray[face][level].getWidth() != std::max(1, size >> level))
 
2493
            {
 
2494
                return false;
 
2495
            }
 
2496
        }
 
2497
    }
 
2498
 
 
2499
    return true;
 
2500
}
 
2501
 
 
2502
bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
 
2503
{
 
2504
    return IsCompressed(getInternalFormat(target, level));
 
2505
}
 
2506
 
 
2507
IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
 
2508
{
 
2509
    return mTexStorage ? mTexStorage->getBaseTexture() : NULL;
 
2510
}
 
2511
 
 
2512
// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
 
2513
void TextureCubeMap::createTexture()
 
2514
{
 
2515
    GLsizei size = mImageArray[0][0].getWidth();
 
2516
    GLint levels = creationLevels(size, 0);
 
2517
    D3DFORMAT d3dfmt = mImageArray[0][0].getD3DFormat();
 
2518
    DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false);
 
2519
 
 
2520
    delete mTexStorage;
 
2521
    mTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size);
 
2522
 
 
2523
    if (mTexStorage->isManaged())
 
2524
    {
 
2525
        int levels = levelCount();
 
2526
 
 
2527
        for (int face = 0; face < 6; face++)
 
2528
        {
 
2529
            for (int level = 0; level < levels; level++)
 
2530
            {
 
2531
                IDirect3DSurface9 *surface = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
 
2532
                mImageArray[face][level].setManagedSurface(surface);
 
2533
            }
 
2534
        }
 
2535
    }
 
2536
 
 
2537
    mDirtyImages = true;
 
2538
}
 
2539
 
 
2540
void TextureCubeMap::updateTexture()
 
2541
{
 
2542
    for (int face = 0; face < 6; face++)
 
2543
    {
 
2544
        int levels = levelCount();
 
2545
        for (int level = 0; level < levels; level++)
 
2546
        {
 
2547
            Image *image = &mImageArray[face][level];
 
2548
 
 
2549
            if (image->isDirty())
 
2550
            {
 
2551
                commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
 
2552
            }
 
2553
        }
 
2554
    }
 
2555
}
 
2556
 
 
2557
void TextureCubeMap::convertToRenderTarget()
 
2558
{
 
2559
    TextureStorageCubeMap *newTexStorage = NULL;
 
2560
 
 
2561
    if (mImageArray[0][0].getWidth() != 0)
 
2562
    {
 
2563
        GLsizei size = mImageArray[0][0].getWidth();
 
2564
        GLint levels = creationLevels(size, 0);
 
2565
        D3DFORMAT d3dfmt = mImageArray[0][0].getD3DFormat();
 
2566
        DWORD d3dusage = GetTextureUsage(d3dfmt, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true);
 
2567
 
 
2568
        newTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size);
 
2569
 
 
2570
        if (mTexStorage != NULL)
 
2571
        {
 
2572
            int levels = levelCount();
 
2573
            for (int f = 0; f < 6; f++)
 
2574
            {
 
2575
                for (int i = 0; i < levels; i++)
 
2576
                {
 
2577
                    IDirect3DSurface9 *source = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
 
2578
                    IDirect3DSurface9 *dest = newTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
 
2579
 
 
2580
                    if (!copyToRenderTarget(dest, source, mTexStorage->isManaged()))
 
2581
                    {
 
2582
                       delete newTexStorage;
 
2583
                       if (source) source->Release();
 
2584
                       if (dest) dest->Release();
 
2585
                       return error(GL_OUT_OF_MEMORY);
 
2586
                    }
 
2587
 
 
2588
                    if (source) source->Release();
 
2589
                    if (dest) dest->Release();
 
2590
                }
 
2591
            }
 
2592
        }
 
2593
    }
 
2594
 
 
2595
    delete mTexStorage;
 
2596
    mTexStorage = newTexStorage;
 
2597
 
 
2598
    mDirtyImages = true;
 
2599
}
 
2600
 
 
2601
void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 
2602
{
 
2603
    redefineImage(faceIndex, level, format, width, height, type);
 
2604
 
 
2605
    Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
 
2606
}
 
2607
 
 
2608
unsigned int TextureCubeMap::faceIndex(GLenum face)
 
2609
{
 
2610
    META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
 
2611
    META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
 
2612
    META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
 
2613
    META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
 
2614
    META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
 
2615
 
 
2616
    return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
 
2617
}
 
2618
 
 
2619
void TextureCubeMap::redefineImage(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
 
2620
{
 
2621
    bool redefined = mImageArray[face][level].redefine(format, width, height, type, false);
 
2622
 
 
2623
    if (mTexStorage && redefined)
 
2624
    {
 
2625
        for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
 
2626
        {
 
2627
            for (int f = 0; f < 6; f++)
 
2628
            {
 
2629
                mImageArray[f][i].markDirty();
 
2630
            }
 
2631
        }
 
2632
 
 
2633
        delete mTexStorage;
 
2634
        mTexStorage = NULL;
 
2635
 
 
2636
        mDirtyImages = true;
 
2637
    }
 
2638
}
 
2639
 
 
2640
void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
 
2641
{
 
2642
    IDirect3DSurface9 *renderTarget = source->getRenderTarget();
 
2643
 
 
2644
    if (!renderTarget)
 
2645
    {
 
2646
        ERR("Failed to retrieve the render target.");
 
2647
        return error(GL_OUT_OF_MEMORY);
 
2648
    }
 
2649
 
 
2650
    unsigned int faceindex = faceIndex(target);
 
2651
    redefineImage(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
 
2652
 
 
2653
    if (!mImageArray[faceindex][level].isRenderableFormat())
 
2654
    {
 
2655
        mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
 
2656
        mDirtyImages = true;
 
2657
    }
 
2658
    else
 
2659
    {
 
2660
        if (!mTexStorage || !mTexStorage->isRenderTarget())
 
2661
        {
 
2662
            convertToRenderTarget();
 
2663
        }
 
2664
        
 
2665
        mImageArray[faceindex][level].markClean();
 
2666
 
 
2667
        ASSERT(width == height);
 
2668
 
 
2669
        if (width > 0 && level < levelCount())
 
2670
        {
 
2671
            RECT sourceRect;
 
2672
            sourceRect.left = x;
 
2673
            sourceRect.right = x + width;
 
2674
            sourceRect.top = y;
 
2675
            sourceRect.bottom = y + height;
 
2676
 
 
2677
            IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level);
 
2678
 
 
2679
            if (dest)
 
2680
            {
 
2681
                getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest);
 
2682
                dest->Release();
 
2683
            }
 
2684
        }
 
2685
    }
 
2686
 
 
2687
    renderTarget->Release();
 
2688
}
 
2689
 
 
2690
void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
 
2691
{
 
2692
    GLsizei size = mImageArray[faceIndex(target)][level].getWidth();
 
2693
 
 
2694
    if (xoffset + width > size || yoffset + height > size)
 
2695
    {
 
2696
        return error(GL_INVALID_VALUE);
 
2697
    }
 
2698
 
 
2699
    IDirect3DSurface9 *renderTarget = source->getRenderTarget();
 
2700
 
 
2701
    if (!renderTarget)
 
2702
    {
 
2703
        ERR("Failed to retrieve the render target.");
 
2704
        return error(GL_OUT_OF_MEMORY);
 
2705
    }
 
2706
 
 
2707
    unsigned int faceindex = faceIndex(target);
 
2708
 
 
2709
    if (!mImageArray[faceindex][level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
 
2710
    {
 
2711
        mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
 
2712
        mDirtyImages = true;
 
2713
    }
 
2714
    else
 
2715
    {
 
2716
        if (!mTexStorage || !mTexStorage->isRenderTarget())
 
2717
        {
 
2718
            convertToRenderTarget();
 
2719
        }
 
2720
        
 
2721
        updateTexture();
 
2722
 
 
2723
        if (level < levelCount())
 
2724
        {
 
2725
            RECT sourceRect;
 
2726
            sourceRect.left = x;
 
2727
            sourceRect.right = x + width;
 
2728
            sourceRect.top = y;
 
2729
            sourceRect.bottom = y + height;
 
2730
 
 
2731
            IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level);
 
2732
 
 
2733
            if (dest)
 
2734
            {
 
2735
                getBlitter()->copy(renderTarget, sourceRect, mImageArray[0][0].getFormat(), xoffset, yoffset, dest);
 
2736
                dest->Release();
 
2737
            }
 
2738
        }
 
2739
    }
 
2740
 
 
2741
    renderTarget->Release();
 
2742
}
 
2743
 
 
2744
void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
 
2745
{
 
2746
    GLenum format = gl::ExtractFormat(internalformat);
 
2747
    GLenum type = gl::ExtractType(internalformat);
 
2748
    D3DFORMAT d3dfmt = ConvertTextureFormatType(format, type);
 
2749
    DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false);
 
2750
 
 
2751
    delete mTexStorage;
 
2752
    mTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size);
 
2753
    mImmutable = true;
 
2754
 
 
2755
    for (int level = 0; level < levels; level++)
 
2756
    {
 
2757
        for (int face = 0; face < 6; face++)
 
2758
        {
 
2759
            mImageArray[face][level].redefine(format, size, size, type, true);
 
2760
            size = std::max(1, size >> 1);
 
2761
        }
 
2762
    }
 
2763
 
 
2764
    for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
 
2765
    {
 
2766
        for (int face = 0; face < 6; face++)
 
2767
        {
 
2768
            mImageArray[face][level].redefine(GL_NONE, 0, 0, GL_UNSIGNED_BYTE, true);
 
2769
        }
 
2770
    }
 
2771
 
 
2772
    if (mTexStorage->isManaged())
 
2773
    {
 
2774
        int levels = levelCount();
 
2775
 
 
2776
        for (int face = 0; face < 6; face++)
 
2777
        {
 
2778
            for (int level = 0; level < levels; level++)
 
2779
            {
 
2780
                IDirect3DSurface9 *surface = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
 
2781
                mImageArray[face][level].setManagedSurface(surface);
 
2782
            }
 
2783
        }
 
2784
    }
 
2785
}
 
2786
 
 
2787
void TextureCubeMap::generateMipmaps()
 
2788
{
 
2789
    if (!isCubeComplete())
 
2790
    {
 
2791
        return error(GL_INVALID_OPERATION);
 
2792
    }
 
2793
 
 
2794
    if (!getContext()->supportsNonPower2Texture())
 
2795
    {
 
2796
        if (!isPow2(mImageArray[0][0].getWidth()))
 
2797
        {
 
2798
            return error(GL_INVALID_OPERATION);
 
2799
        }
 
2800
    }
 
2801
 
 
2802
    // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
 
2803
    unsigned int q = log2(mImageArray[0][0].getWidth());
 
2804
    for (unsigned int f = 0; f < 6; f++)
 
2805
    {
 
2806
        for (unsigned int i = 1; i <= q; i++)
 
2807
        {
 
2808
            redefineImage(f, i, mImageArray[f][0].getFormat(),
 
2809
                                std::max(mImageArray[f][0].getWidth() >> i, 1),
 
2810
                                std::max(mImageArray[f][0].getWidth() >> i, 1),
 
2811
                                mImageArray[f][0].getType());
 
2812
        }
 
2813
    }
 
2814
 
 
2815
    if (mTexStorage && mTexStorage->isRenderTarget())
 
2816
    {
 
2817
        for (unsigned int f = 0; f < 6; f++)
 
2818
        {
 
2819
            for (unsigned int i = 1; i <= q; i++)
 
2820
            {
 
2821
                IDirect3DSurface9 *upper = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
 
2822
                IDirect3DSurface9 *lower = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
 
2823
 
 
2824
                if (upper != NULL && lower != NULL)
 
2825
                {
 
2826
                    getBlitter()->boxFilter(upper, lower);
 
2827
                }
 
2828
 
 
2829
                if (upper != NULL) upper->Release();
 
2830
                if (lower != NULL) lower->Release();
 
2831
 
 
2832
                mImageArray[f][i].markClean();
 
2833
            }
 
2834
        }
 
2835
    }
 
2836
    else
 
2837
    {
 
2838
        for (unsigned int f = 0; f < 6; f++)
 
2839
        {
 
2840
            for (unsigned int i = 1; i <= q; i++)
 
2841
            {
 
2842
                if (mImageArray[f][i].getSurface() == NULL)
 
2843
                {
 
2844
                    return error(GL_OUT_OF_MEMORY);
 
2845
                }
 
2846
 
 
2847
                if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].getSurface(), NULL, NULL, mImageArray[f][i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0)))
 
2848
                {
 
2849
                    ERR(" failed to load filter %d to %d.", i - 1, i);
 
2850
                }
 
2851
 
 
2852
                mImageArray[f][i].markDirty();
 
2853
            }
 
2854
        }
 
2855
    }
 
2856
}
 
2857
 
 
2858
Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
 
2859
{
 
2860
    if (!IsCubemapTextureTarget(target))
 
2861
    {
 
2862
        return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
 
2863
    }
 
2864
 
 
2865
    unsigned int face = faceIndex(target);
 
2866
 
 
2867
    if (mFaceProxies[face] == NULL)
 
2868
    {
 
2869
        mFaceProxies[face] = new Renderbuffer(id(), new RenderbufferTextureCubeMap(this, target));
 
2870
    }
 
2871
 
 
2872
    return mFaceProxies[face];
 
2873
}
 
2874
 
 
2875
// Increments refcount on surface.
 
2876
// caller must Release() the returned surface
 
2877
IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
 
2878
{
 
2879
    ASSERT(IsCubemapTextureTarget(target));
 
2880
 
 
2881
    // ensure the underlying texture is created
 
2882
    if (getStorage(true) == NULL)
 
2883
    {
 
2884
        return NULL;
 
2885
    }
 
2886
 
 
2887
    updateTexture();
 
2888
    
 
2889
    return mTexStorage->getCubeMapSurface(target, 0);
 
2890
}
 
2891
 
 
2892
TextureStorage *TextureCubeMap::getStorage(bool renderTarget)
 
2893
{
 
2894
    if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
 
2895
    {
 
2896
        if (renderTarget)
 
2897
        {
 
2898
            convertToRenderTarget();
 
2899
        }
 
2900
        else
 
2901
        {
 
2902
            createTexture();
 
2903
        }
 
2904
    }
 
2905
 
 
2906
    return mTexStorage;
 
2907
}
 
2908
 
 
2909
}