blob: 8f4488e64f31e1a79bcb4c53b3bc98b430f97c9c [file] [log] [blame]
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001//
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00002// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00003// 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>
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000016
17#include "common/debug.h"
18
19#include "libEGL/Display.h"
20
21#include "libGLESv2/main.h"
22#include "libGLESv2/mathutil.h"
23#include "libGLESv2/utilities.h"
24#include "libGLESv2/Blit.h"
25#include "libGLESv2/Framebuffer.h"
26
27namespace gl
28{
29unsigned int TextureStorage::mCurrentTextureSerial = 1;
30
daniel@transgaming.com6b1a0a02012-10-17 18:22:47 +000031static D3DFORMAT ConvertTextureInternalFormat(GLint internalformat)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000032{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +000033 switch (internalformat)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000034 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +000035 case GL_DEPTH_COMPONENT16:
36 case GL_DEPTH_COMPONENT32_OES:
37 case GL_DEPTH24_STENCIL8_OES:
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000038 return D3DFMT_INTZ;
daniel@transgaming.com6452adf2012-10-17 18:22:35 +000039 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
40 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000041 return D3DFMT_DXT1;
daniel@transgaming.com6452adf2012-10-17 18:22:35 +000042 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000043 return D3DFMT_DXT3;
daniel@transgaming.com6452adf2012-10-17 18:22:35 +000044 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000045 return D3DFMT_DXT5;
daniel@transgaming.com6452adf2012-10-17 18:22:35 +000046 case GL_RGBA32F_EXT:
47 case GL_RGB32F_EXT:
48 case GL_ALPHA32F_EXT:
49 case GL_LUMINANCE32F_EXT:
50 case GL_LUMINANCE_ALPHA32F_EXT:
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000051 return D3DFMT_A32B32G32R32F;
daniel@transgaming.com6452adf2012-10-17 18:22:35 +000052 case GL_RGBA16F_EXT:
53 case GL_RGB16F_EXT:
54 case GL_ALPHA16F_EXT:
55 case GL_LUMINANCE16F_EXT:
56 case GL_LUMINANCE_ALPHA16F_EXT:
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000057 return D3DFMT_A16B16G16R16F;
daniel@transgaming.com6452adf2012-10-17 18:22:35 +000058 case GL_LUMINANCE8_EXT:
59 if (getContext()->supportsLuminanceTextures())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000060 {
61 return D3DFMT_L8;
62 }
daniel@transgaming.com6452adf2012-10-17 18:22:35 +000063 break;
64 case GL_LUMINANCE8_ALPHA8_EXT:
65 if (getContext()->supportsLuminanceAlphaTextures())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000066 {
67 return D3DFMT_A8L8;
68 }
daniel@transgaming.com6452adf2012-10-17 18:22:35 +000069 break;
70 case GL_RGB8_OES:
daniel@transgaming.com51278032012-10-17 18:22:51 +000071 case GL_RGB565:
daniel@transgaming.com6452adf2012-10-17 18:22:35 +000072 return D3DFMT_X8R8G8B8;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000073 }
74
75 return D3DFMT_A8R8G8B8;
76}
77
78static bool IsTextureFormatRenderable(D3DFORMAT format)
79{
80 if (format == D3DFMT_INTZ)
81 {
82 return true;
83 }
84 switch(format)
85 {
86 case D3DFMT_L8:
87 case D3DFMT_A8L8:
88 case D3DFMT_DXT1:
89 case D3DFMT_DXT3:
90 case D3DFMT_DXT5:
91 return false;
92 case D3DFMT_A8R8G8B8:
93 case D3DFMT_X8R8G8B8:
94 case D3DFMT_A16B16G16R16F:
95 case D3DFMT_A32B32G32R32F:
96 return true;
97 default:
98 UNREACHABLE();
99 }
100
101 return false;
102}
103
104static inline DWORD GetTextureUsage(D3DFORMAT d3dfmt, GLenum glusage, bool forceRenderable)
105{
106 DWORD d3dusage = 0;
107
108 if (d3dfmt == D3DFMT_INTZ)
109 {
110 d3dusage |= D3DUSAGE_DEPTHSTENCIL;
111 }
112 else if(forceRenderable || (IsTextureFormatRenderable(d3dfmt) && (glusage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE)))
113 {
114 d3dusage |= D3DUSAGE_RENDERTARGET;
115 }
116 return d3dusage;
117}
118
jbauman@chromium.org68715282012-07-12 23:28:41 +0000119static void MakeValidSize(bool isImage, bool isCompressed, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset) {
120 int upsampleCount = 0;
121
122 if (isCompressed)
123 {
124 // Don't expand the size of full textures that are at least 4x4
125 // already.
126 if (isImage || *requestWidth < 4 || *requestHeight < 4)
127 {
128 while (*requestWidth % 4 != 0 || *requestHeight % 4 != 0)
129 {
130 *requestWidth <<= 1;
131 *requestHeight <<= 1;
132 upsampleCount++;
133 }
134 }
135 }
136 *levelOffset = upsampleCount;
137}
138
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000139Image::Image()
140{
141 mWidth = 0;
142 mHeight = 0;
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000143 mInternalFormat = GL_NONE;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000144
145 mSurface = NULL;
146
147 mDirty = false;
148
149 mD3DPool = D3DPOOL_SYSTEMMEM;
150 mD3DFormat = D3DFMT_UNKNOWN;
151}
152
153Image::~Image()
154{
155 if (mSurface)
156 {
157 mSurface->Release();
158 }
159}
160
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000161bool Image::redefine(GLint internalformat, GLsizei width, GLsizei height, bool forceRelease)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000162{
163 if (mWidth != width ||
164 mHeight != height ||
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000165 mInternalFormat != internalformat ||
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000166 forceRelease)
167 {
168 mWidth = width;
169 mHeight = height;
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000170 mInternalFormat = internalformat;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000171 // compute the d3d format that will be used
daniel@transgaming.com6b1a0a02012-10-17 18:22:47 +0000172 mD3DFormat = ConvertTextureInternalFormat(internalformat);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000173
174 if (mSurface)
175 {
176 mSurface->Release();
177 mSurface = NULL;
178 }
179
180 return true;
181 }
182
183 return false;
184}
185
186void Image::createSurface()
187{
188 if(mSurface)
189 {
190 return;
191 }
192
193 IDirect3DTexture9 *newTexture = NULL;
194 IDirect3DSurface9 *newSurface = NULL;
195 const D3DPOOL poolToUse = D3DPOOL_SYSTEMMEM;
196 const D3DFORMAT d3dFormat = getD3DFormat();
197 ASSERT(d3dFormat != D3DFMT_INTZ); // We should never get here for depth textures
198
199 if (mWidth != 0 && mHeight != 0)
200 {
201 int levelToFetch = 0;
202 GLsizei requestWidth = mWidth;
203 GLsizei requestHeight = mHeight;
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000204 MakeValidSize(true, IsCompressed(mInternalFormat), &requestWidth, &requestHeight, &levelToFetch);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000205
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
225HRESULT 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
242void Image::unlock()
243{
244 if (mSurface)
245 {
246 HRESULT result = mSurface->UnlockRect();
247 ASSERT(SUCCEEDED(result));
248 }
249}
250
251bool Image::isRenderableFormat() const
252{
253 return IsTextureFormatRenderable(getD3DFormat());
254}
255
256D3DFORMAT 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
265IDirect3DSurface9 *Image::getSurface()
266{
267 createSurface();
268
269 return mSurface;
270}
271
272void 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
288void 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.
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000317void Image::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000318 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
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000333
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000334 GLsizei inputPitch = ComputePitch(width, mInternalFormat, unpackAlignment);
335
336 switch (mInternalFormat)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000337 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000338 case GL_ALPHA8_EXT:
339 if (supportsSSE2())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000340 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000341 loadAlphaDataSSE2(width, height, inputPitch, input, locked.Pitch, locked.pBits);
342 }
343 else
344 {
345 loadAlphaData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000346 }
347 break;
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000348 case GL_LUMINANCE8_EXT:
349 loadLuminanceData(width, height, inputPitch, input, locked.Pitch, locked.pBits, getD3DFormat() == D3DFMT_L8);
350 break;
351 case GL_ALPHA32F_EXT:
352 loadAlphaFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
353 break;
354 case GL_LUMINANCE32F_EXT:
355 loadLuminanceFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
356 break;
357 case GL_ALPHA16F_EXT:
358 loadAlphaHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
359 break;
360 case GL_LUMINANCE16F_EXT:
361 loadLuminanceHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
362 break;
363 case GL_LUMINANCE8_ALPHA8_EXT:
364 loadLuminanceAlphaData(width, height, inputPitch, input, locked.Pitch, locked.pBits, getD3DFormat() == D3DFMT_A8L8);
365 break;
366 case GL_LUMINANCE_ALPHA32F_EXT:
367 loadLuminanceAlphaFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
368 break;
369 case GL_LUMINANCE_ALPHA16F_EXT:
370 loadLuminanceAlphaHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
371 break;
372 case GL_RGB8_OES:
373 loadRGBUByteData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
374 break;
375 case GL_RGB565:
376 loadRGB565Data(width, height, inputPitch, input, locked.Pitch, locked.pBits);
377 break;
378 case GL_RGBA8_OES:
379 if (supportsSSE2())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000380 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000381 loadRGBAUByteDataSSE2(width, height, inputPitch, input, locked.Pitch, locked.pBits);
382 }
383 else
384 {
385 loadRGBAUByteData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000386 }
387 break;
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000388 case GL_RGBA4:
389 loadRGBA4444Data(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000390 break;
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000391 case GL_RGB5_A1:
392 loadRGBA5551Data(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000393 break;
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000394 case GL_BGRA8_EXT:
395 loadBGRAData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000396 break;
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000397 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
398 case GL_RGB32F_EXT:
399 loadRGBFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000400 break;
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000401 case GL_RGB16F_EXT:
402 loadRGBHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
403 break;
404 case GL_RGBA32F_EXT:
405 loadRGBAFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
406 break;
407 case GL_RGBA16F_EXT:
408 loadRGBAHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
409 break;
410 default: UNREACHABLE();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000411 }
412
413 unlock();
414}
415
416void Image::loadAlphaData(GLsizei width, GLsizei height,
417 int inputPitch, const void *input, size_t outputPitch, void *output) const
418{
419 const unsigned char *source = NULL;
420 unsigned char *dest = NULL;
421
422 for (int y = 0; y < height; y++)
423 {
424 source = static_cast<const unsigned char*>(input) + y * inputPitch;
425 dest = static_cast<unsigned char*>(output) + y * outputPitch;
426 for (int x = 0; x < width; x++)
427 {
428 dest[4 * x + 0] = 0;
429 dest[4 * x + 1] = 0;
430 dest[4 * x + 2] = 0;
431 dest[4 * x + 3] = source[x];
432 }
433 }
434}
435
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000436void Image::loadAlphaFloatData(GLsizei width, GLsizei height,
437 int inputPitch, const void *input, size_t outputPitch, void *output) const
438{
439 const float *source = NULL;
440 float *dest = NULL;
441
442 for (int y = 0; y < height; y++)
443 {
444 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
445 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
446 for (int x = 0; x < width; x++)
447 {
448 dest[4 * x + 0] = 0;
449 dest[4 * x + 1] = 0;
450 dest[4 * x + 2] = 0;
451 dest[4 * x + 3] = source[x];
452 }
453 }
454}
455
456void Image::loadAlphaHalfFloatData(GLsizei width, GLsizei height,
457 int inputPitch, const void *input, size_t outputPitch, void *output) const
458{
459 const unsigned short *source = NULL;
460 unsigned short *dest = NULL;
461
462 for (int y = 0; y < height; y++)
463 {
464 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
465 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch);
466 for (int x = 0; x < width; x++)
467 {
468 dest[4 * x + 0] = 0;
469 dest[4 * x + 1] = 0;
470 dest[4 * x + 2] = 0;
471 dest[4 * x + 3] = source[x];
472 }
473 }
474}
475
476void Image::loadLuminanceData(GLsizei width, GLsizei height,
477 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
478{
479 const unsigned char *source = NULL;
480 unsigned char *dest = NULL;
481
482 for (int y = 0; y < height; y++)
483 {
484 source = static_cast<const unsigned char*>(input) + y * inputPitch;
485 dest = static_cast<unsigned char*>(output) + y * outputPitch;
486
487 if (!native) // BGRA8 destination format
488 {
489 for (int x = 0; x < width; x++)
490 {
491 dest[4 * x + 0] = source[x];
492 dest[4 * x + 1] = source[x];
493 dest[4 * x + 2] = source[x];
494 dest[4 * x + 3] = 0xFF;
495 }
496 }
497 else // L8 destination format
498 {
499 memcpy(dest, source, width);
500 }
501 }
502}
503
504void Image::loadLuminanceFloatData(GLsizei width, GLsizei height,
505 int inputPitch, const void *input, size_t outputPitch, void *output) const
506{
507 const float *source = NULL;
508 float *dest = NULL;
509
510 for (int y = 0; y < height; y++)
511 {
512 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
513 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
514 for (int x = 0; x < width; x++)
515 {
516 dest[4 * x + 0] = source[x];
517 dest[4 * x + 1] = source[x];
518 dest[4 * x + 2] = source[x];
519 dest[4 * x + 3] = 1.0f;
520 }
521 }
522}
523
524void Image::loadLuminanceHalfFloatData(GLsizei width, GLsizei height,
525 int inputPitch, const void *input, size_t outputPitch, void *output) const
526{
527 const unsigned short *source = NULL;
528 unsigned short *dest = NULL;
529
530 for (int y = 0; y < height; y++)
531 {
532 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
533 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch);
534 for (int x = 0; x < width; x++)
535 {
536 dest[4 * x + 0] = source[x];
537 dest[4 * x + 1] = source[x];
538 dest[4 * x + 2] = source[x];
539 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
540 }
541 }
542}
543
544void Image::loadLuminanceAlphaData(GLsizei width, GLsizei height,
545 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
546{
547 const unsigned char *source = NULL;
548 unsigned char *dest = NULL;
549
550 for (int y = 0; y < height; y++)
551 {
552 source = static_cast<const unsigned char*>(input) + y * inputPitch;
553 dest = static_cast<unsigned char*>(output) + y * outputPitch;
554
555 if (!native) // BGRA8 destination format
556 {
557 for (int x = 0; x < width; x++)
558 {
559 dest[4 * x + 0] = source[2*x+0];
560 dest[4 * x + 1] = source[2*x+0];
561 dest[4 * x + 2] = source[2*x+0];
562 dest[4 * x + 3] = source[2*x+1];
563 }
564 }
565 else
566 {
567 memcpy(dest, source, width * 2);
568 }
569 }
570}
571
572void Image::loadLuminanceAlphaFloatData(GLsizei width, GLsizei height,
573 int inputPitch, const void *input, size_t outputPitch, void *output) const
574{
575 const float *source = NULL;
576 float *dest = NULL;
577
578 for (int y = 0; y < height; y++)
579 {
580 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
581 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
582 for (int x = 0; x < width; x++)
583 {
584 dest[4 * x + 0] = source[2*x+0];
585 dest[4 * x + 1] = source[2*x+0];
586 dest[4 * x + 2] = source[2*x+0];
587 dest[4 * x + 3] = source[2*x+1];
588 }
589 }
590}
591
592void Image::loadLuminanceAlphaHalfFloatData(GLsizei width, GLsizei height,
593 int inputPitch, const void *input, size_t outputPitch, void *output) const
594{
595 const unsigned short *source = NULL;
596 unsigned short *dest = NULL;
597
598 for (int y = 0; y < height; y++)
599 {
600 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
601 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch);
602 for (int x = 0; x < width; x++)
603 {
604 dest[4 * x + 0] = source[2*x+0];
605 dest[4 * x + 1] = source[2*x+0];
606 dest[4 * x + 2] = source[2*x+0];
607 dest[4 * x + 3] = source[2*x+1];
608 }
609 }
610}
611
612void Image::loadRGBUByteData(GLsizei width, GLsizei height,
613 int inputPitch, const void *input, size_t outputPitch, void *output) const
614{
615 const unsigned char *source = NULL;
616 unsigned char *dest = NULL;
617
618 for (int y = 0; y < height; y++)
619 {
620 source = static_cast<const unsigned char*>(input) + y * inputPitch;
621 dest = static_cast<unsigned char*>(output) + y * outputPitch;
622 for (int x = 0; x < width; x++)
623 {
624 dest[4 * x + 0] = source[x * 3 + 2];
625 dest[4 * x + 1] = source[x * 3 + 1];
626 dest[4 * x + 2] = source[x * 3 + 0];
627 dest[4 * x + 3] = 0xFF;
628 }
629 }
630}
631
632void Image::loadRGB565Data(GLsizei width, GLsizei height,
633 int inputPitch, const void *input, size_t outputPitch, void *output) const
634{
635 const unsigned short *source = NULL;
636 unsigned char *dest = NULL;
637
638 for (int y = 0; y < height; y++)
639 {
640 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
641 dest = static_cast<unsigned char*>(output) + y * outputPitch;
642 for (int x = 0; x < width; x++)
643 {
644 unsigned short rgba = source[x];
645 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
646 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
647 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
648 dest[4 * x + 3] = 0xFF;
649 }
650 }
651}
652
653void Image::loadRGBFloatData(GLsizei width, GLsizei height,
654 int inputPitch, const void *input, size_t outputPitch, void *output) const
655{
656 const float *source = NULL;
657 float *dest = NULL;
658
659 for (int y = 0; y < height; y++)
660 {
661 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
662 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
663 for (int x = 0; x < width; x++)
664 {
665 dest[4 * x + 0] = source[x * 3 + 0];
666 dest[4 * x + 1] = source[x * 3 + 1];
667 dest[4 * x + 2] = source[x * 3 + 2];
668 dest[4 * x + 3] = 1.0f;
669 }
670 }
671}
672
673void Image::loadRGBHalfFloatData(GLsizei width, GLsizei height,
674 int inputPitch, const void *input, size_t outputPitch, void *output) const
675{
676 const unsigned short *source = NULL;
677 unsigned short *dest = NULL;
678
679 for (int y = 0; y < height; y++)
680 {
681 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
682 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch);
683 for (int x = 0; x < width; x++)
684 {
685 dest[4 * x + 0] = source[x * 3 + 0];
686 dest[4 * x + 1] = source[x * 3 + 1];
687 dest[4 * x + 2] = source[x * 3 + 2];
688 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
689 }
690 }
691}
692
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000693void Image::loadRGBAUByteData(GLsizei width, GLsizei height,
694 int inputPitch, const void *input, size_t outputPitch, void *output) const
695{
696 const unsigned int *source = NULL;
697 unsigned int *dest = NULL;
698 for (int y = 0; y < height; y++)
699 {
700 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
701 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + y * outputPitch);
702
703 for (int x = 0; x < width; x++)
704 {
705 unsigned int rgba = source[x];
706 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
707 }
708 }
709}
710
711void Image::loadRGBA4444Data(GLsizei width, GLsizei height,
712 int inputPitch, const void *input, size_t outputPitch, void *output) const
713{
714 const unsigned short *source = NULL;
715 unsigned char *dest = NULL;
716
717 for (int y = 0; y < height; y++)
718 {
719 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
720 dest = static_cast<unsigned char*>(output) + y * outputPitch;
721 for (int x = 0; x < width; x++)
722 {
723 unsigned short rgba = source[x];
724 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
725 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
726 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
727 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
728 }
729 }
730}
731
732void Image::loadRGBA5551Data(GLsizei width, GLsizei height,
733 int inputPitch, const void *input, size_t outputPitch, void *output) const
734{
735 const unsigned short *source = NULL;
736 unsigned char *dest = NULL;
737
738 for (int y = 0; y < height; y++)
739 {
740 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
741 dest = static_cast<unsigned char*>(output) + y * outputPitch;
742 for (int x = 0; x < width; x++)
743 {
744 unsigned short rgba = source[x];
745 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
746 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
747 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
748 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
749 }
750 }
751}
752
753void Image::loadRGBAFloatData(GLsizei width, GLsizei height,
754 int inputPitch, const void *input, size_t outputPitch, void *output) const
755{
756 const float *source = NULL;
757 float *dest = NULL;
758
759 for (int y = 0; y < height; y++)
760 {
761 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
762 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
763 memcpy(dest, source, width * 16);
764 }
765}
766
767void Image::loadRGBAHalfFloatData(GLsizei width, GLsizei height,
768 int inputPitch, const void *input, size_t outputPitch, void *output) const
769{
770 const unsigned char *source = NULL;
771 unsigned char *dest = NULL;
772
773 for (int y = 0; y < height; y++)
774 {
775 source = static_cast<const unsigned char*>(input) + y * inputPitch;
776 dest = static_cast<unsigned char*>(output) + y * outputPitch;
777 memcpy(dest, source, width * 8);
778 }
779}
780
781void Image::loadBGRAData(GLsizei width, GLsizei height,
782 int inputPitch, const void *input, size_t outputPitch, void *output) const
783{
784 const unsigned char *source = NULL;
785 unsigned char *dest = NULL;
786
787 for (int y = 0; y < height; y++)
788 {
789 source = static_cast<const unsigned char*>(input) + y * inputPitch;
790 dest = static_cast<unsigned char*>(output) + y * outputPitch;
791 memcpy(dest, source, width*4);
792 }
793}
794
795void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
796 const void *input) {
797 ASSERT(xoffset % 4 == 0);
798 ASSERT(yoffset % 4 == 0);
799
800 RECT lockRect = {
801 xoffset, yoffset,
802 xoffset + width, yoffset + height
803 };
804
805 D3DLOCKED_RECT locked;
806 HRESULT result = lock(&locked, &lockRect);
807 if (FAILED(result))
808 {
809 return;
810 }
811
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000812 GLsizei inputSize = ComputeCompressedSize(width, height, mInternalFormat);
813 GLsizei inputPitch = ComputeCompressedPitch(width, mInternalFormat);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000814 int rows = inputSize / inputPitch;
815 for (int i = 0; i < rows; ++i)
816 {
817 memcpy((void*)((BYTE*)locked.pBits + i * locked.Pitch), (void*)((BYTE*)input + i * inputPitch), inputPitch);
818 }
819
820 unlock();
821}
822
823// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
824void Image::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
825{
826 IDirect3DDevice9 *device = getDevice();
827 IDirect3DSurface9 *renderTargetData = NULL;
828 D3DSURFACE_DESC description;
829 renderTarget->GetDesc(&description);
830
831 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
832
833 if (FAILED(result))
834 {
835 ERR("Could not create matching destination surface.");
836 return error(GL_OUT_OF_MEMORY);
837 }
838
839 result = device->GetRenderTargetData(renderTarget, renderTargetData);
840
841 if (FAILED(result))
842 {
843 ERR("GetRenderTargetData unexpectedly failed.");
844 renderTargetData->Release();
845 return error(GL_OUT_OF_MEMORY);
846 }
847
848 RECT sourceRect = {x, y, x + width, y + height};
849 RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height};
850
851 if (isRenderableFormat())
852 {
853 result = D3DXLoadSurfaceFromSurface(getSurface(), NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0);
854
855 if (FAILED(result))
856 {
857 ERR("Copying surfaces unexpectedly failed.");
858 renderTargetData->Release();
859 return error(GL_OUT_OF_MEMORY);
860 }
861 }
862 else
863 {
864 D3DLOCKED_RECT sourceLock = {0};
865 result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
866
867 if (FAILED(result))
868 {
869 ERR("Failed to lock the source surface (rectangle might be invalid).");
870 renderTargetData->Release();
871 return error(GL_OUT_OF_MEMORY);
872 }
873
874 D3DLOCKED_RECT destLock = {0};
875 result = lock(&destLock, &destRect);
876
877 if (FAILED(result))
878 {
879 ERR("Failed to lock the destination surface (rectangle might be invalid).");
880 renderTargetData->UnlockRect();
881 renderTargetData->Release();
882 return error(GL_OUT_OF_MEMORY);
883 }
884
885 if (destLock.pBits && sourceLock.pBits)
886 {
887 unsigned char *source = (unsigned char*)sourceLock.pBits;
888 unsigned char *dest = (unsigned char*)destLock.pBits;
889
890 switch (description.Format)
891 {
892 case D3DFMT_X8R8G8B8:
893 case D3DFMT_A8R8G8B8:
894 switch(getD3DFormat())
895 {
896 case D3DFMT_L8:
897 for(int y = 0; y < height; y++)
898 {
899 for(int x = 0; x < width; x++)
900 {
901 dest[x] = source[x * 4 + 2];
902 }
903
904 source += sourceLock.Pitch;
905 dest += destLock.Pitch;
906 }
907 break;
908 case D3DFMT_A8L8:
909 for(int y = 0; y < height; y++)
910 {
911 for(int x = 0; x < width; x++)
912 {
913 dest[x * 2 + 0] = source[x * 4 + 2];
914 dest[x * 2 + 1] = source[x * 4 + 3];
915 }
916
917 source += sourceLock.Pitch;
918 dest += destLock.Pitch;
919 }
920 break;
921 default:
922 UNREACHABLE();
923 }
924 break;
925 case D3DFMT_R5G6B5:
926 switch(getD3DFormat())
927 {
928 case D3DFMT_L8:
929 for(int y = 0; y < height; y++)
930 {
931 for(int x = 0; x < width; x++)
932 {
933 unsigned char red = source[x * 2 + 1] & 0xF8;
934 dest[x] = red | (red >> 5);
935 }
936
937 source += sourceLock.Pitch;
938 dest += destLock.Pitch;
939 }
940 break;
941 default:
942 UNREACHABLE();
943 }
944 break;
945 case D3DFMT_A1R5G5B5:
946 switch(getD3DFormat())
947 {
948 case D3DFMT_L8:
949 for(int y = 0; y < height; y++)
950 {
951 for(int x = 0; x < width; x++)
952 {
953 unsigned char red = source[x * 2 + 1] & 0x7C;
954 dest[x] = (red << 1) | (red >> 4);
955 }
956
957 source += sourceLock.Pitch;
958 dest += destLock.Pitch;
959 }
960 break;
961 case D3DFMT_A8L8:
962 for(int y = 0; y < height; y++)
963 {
964 for(int x = 0; x < width; x++)
965 {
966 unsigned char red = source[x * 2 + 1] & 0x7C;
967 dest[x * 2 + 0] = (red << 1) | (red >> 4);
968 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
969 }
970
971 source += sourceLock.Pitch;
972 dest += destLock.Pitch;
973 }
974 break;
975 default:
976 UNREACHABLE();
977 }
978 break;
979 default:
980 UNREACHABLE();
981 }
982 }
983
984 unlock();
985 renderTargetData->UnlockRect();
986 }
987
988 renderTargetData->Release();
989
990 mDirty = true;
991}
992
993TextureStorage::TextureStorage(DWORD usage)
994 : mD3DUsage(usage),
995 mD3DPool(getDisplay()->getTexturePool(usage)),
jbauman@chromium.org68715282012-07-12 23:28:41 +0000996 mTextureSerial(issueTextureSerial()),
997 mLodOffset(0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000998{
999}
1000
1001TextureStorage::~TextureStorage()
1002{
1003}
1004
1005bool TextureStorage::isRenderTarget() const
1006{
1007 return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0;
1008}
1009
1010bool TextureStorage::isManaged() const
1011{
1012 return (mD3DPool == D3DPOOL_MANAGED);
1013}
1014
1015D3DPOOL TextureStorage::getPool() const
1016{
1017 return mD3DPool;
1018}
1019
1020DWORD TextureStorage::getUsage() const
1021{
1022 return mD3DUsage;
1023}
1024
1025unsigned int TextureStorage::getTextureSerial() const
1026{
1027 return mTextureSerial;
1028}
1029
1030unsigned int TextureStorage::issueTextureSerial()
1031{
1032 return mCurrentTextureSerial++;
1033}
1034
jbauman@chromium.org68715282012-07-12 23:28:41 +00001035int TextureStorage::getLodOffset() const
1036{
1037 return mLodOffset;
1038}
1039
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001040Texture::Texture(GLuint id) : RefCountObject(id)
1041{
1042 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
1043 mMagFilter = GL_LINEAR;
1044 mWrapS = GL_REPEAT;
1045 mWrapT = GL_REPEAT;
1046 mDirtyParameters = true;
1047 mUsage = GL_NONE;
daniel@transgaming.com07ab8412012-07-12 15:17:09 +00001048 mMaxAnisotropy = 1.0f;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001049
1050 mDirtyImages = true;
1051
1052 mImmutable = false;
1053}
1054
1055Texture::~Texture()
1056{
1057}
1058
1059// Returns true on successful filter state update (valid enum parameter)
1060bool Texture::setMinFilter(GLenum filter)
1061{
1062 switch (filter)
1063 {
1064 case GL_NEAREST:
1065 case GL_LINEAR:
1066 case GL_NEAREST_MIPMAP_NEAREST:
1067 case GL_LINEAR_MIPMAP_NEAREST:
1068 case GL_NEAREST_MIPMAP_LINEAR:
1069 case GL_LINEAR_MIPMAP_LINEAR:
1070 {
1071 if (mMinFilter != filter)
1072 {
1073 mMinFilter = filter;
1074 mDirtyParameters = true;
1075 }
1076 return true;
1077 }
1078 default:
1079 return false;
1080 }
1081}
1082
1083// Returns true on successful filter state update (valid enum parameter)
1084bool Texture::setMagFilter(GLenum filter)
1085{
1086 switch (filter)
1087 {
1088 case GL_NEAREST:
1089 case GL_LINEAR:
1090 {
1091 if (mMagFilter != filter)
1092 {
1093 mMagFilter = filter;
1094 mDirtyParameters = true;
1095 }
1096 return true;
1097 }
1098 default:
1099 return false;
1100 }
1101}
1102
1103// Returns true on successful wrap state update (valid enum parameter)
1104bool Texture::setWrapS(GLenum wrap)
1105{
1106 switch (wrap)
1107 {
1108 case GL_REPEAT:
1109 case GL_CLAMP_TO_EDGE:
1110 case GL_MIRRORED_REPEAT:
1111 {
1112 if (mWrapS != wrap)
1113 {
1114 mWrapS = wrap;
1115 mDirtyParameters = true;
1116 }
1117 return true;
1118 }
1119 default:
1120 return false;
1121 }
1122}
1123
1124// Returns true on successful wrap state update (valid enum parameter)
1125bool Texture::setWrapT(GLenum wrap)
1126{
1127 switch (wrap)
1128 {
1129 case GL_REPEAT:
1130 case GL_CLAMP_TO_EDGE:
1131 case GL_MIRRORED_REPEAT:
1132 {
1133 if (mWrapT != wrap)
1134 {
1135 mWrapT = wrap;
1136 mDirtyParameters = true;
1137 }
1138 return true;
1139 }
1140 default:
1141 return false;
1142 }
1143}
1144
daniel@transgaming.com07ab8412012-07-12 15:17:09 +00001145// Returns true on successful max anisotropy update (valid anisotropy value)
1146bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
1147{
1148 textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
1149 if (textureMaxAnisotropy < 1.0f)
1150 {
1151 return false;
1152 }
1153 if (mMaxAnisotropy != textureMaxAnisotropy)
1154 {
1155 mMaxAnisotropy = textureMaxAnisotropy;
1156 mDirtyParameters = true;
1157 }
1158 return true;
1159}
1160
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001161// Returns true on successful usage state update (valid enum parameter)
1162bool Texture::setUsage(GLenum usage)
1163{
1164 switch (usage)
1165 {
1166 case GL_NONE:
1167 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
1168 mUsage = usage;
1169 return true;
1170 default:
1171 return false;
1172 }
1173}
1174
1175GLenum Texture::getMinFilter() const
1176{
1177 return mMinFilter;
1178}
1179
1180GLenum Texture::getMagFilter() const
1181{
1182 return mMagFilter;
1183}
1184
1185GLenum Texture::getWrapS() const
1186{
1187 return mWrapS;
1188}
1189
1190GLenum Texture::getWrapT() const
1191{
1192 return mWrapT;
1193}
1194
daniel@transgaming.com07ab8412012-07-12 15:17:09 +00001195float Texture::getMaxAnisotropy() const
1196{
1197 return mMaxAnisotropy;
1198}
1199
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001200GLenum Texture::getUsage() const
1201{
1202 return mUsage;
1203}
1204
1205void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
1206{
1207 if (pixels != NULL)
1208 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001209 image->loadData(0, 0, image->getWidth(), image->getHeight(), unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001210 mDirtyImages = true;
1211 }
1212}
1213
1214void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
1215{
1216 if (pixels != NULL)
1217 {
1218 image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), pixels);
1219 mDirtyImages = true;
1220 }
1221}
1222
1223bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image)
1224{
1225 if (pixels != NULL)
1226 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001227 image->loadData(xoffset, yoffset, width, height, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001228 mDirtyImages = true;
1229 }
1230
1231 return true;
1232}
1233
1234bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image)
1235{
1236 if (pixels != NULL)
1237 {
1238 image->loadCompressedData(xoffset, yoffset, width, height, pixels);
1239 mDirtyImages = true;
1240 }
1241
1242 return true;
1243}
1244
1245IDirect3DBaseTexture9 *Texture::getTexture()
1246{
1247 if (!isSamplerComplete())
1248 {
1249 return NULL;
1250 }
1251
1252 // ensure the underlying texture is created
1253 if (getStorage(false) == NULL)
1254 {
1255 return NULL;
1256 }
1257
1258 updateTexture();
1259
1260 return getBaseTexture();
1261}
1262
1263bool Texture::hasDirtyParameters() const
1264{
1265 return mDirtyParameters;
1266}
1267
1268bool Texture::hasDirtyImages() const
1269{
1270 return mDirtyImages;
1271}
1272
1273void Texture::resetDirty()
1274{
1275 mDirtyParameters = false;
1276 mDirtyImages = false;
1277}
1278
1279unsigned int Texture::getTextureSerial()
1280{
1281 TextureStorage *texture = getStorage(false);
1282 return texture ? texture->getTextureSerial() : 0;
1283}
1284
1285unsigned int Texture::getRenderTargetSerial(GLenum target)
1286{
1287 TextureStorage *texture = getStorage(true);
1288 return texture ? texture->getRenderTargetSerial(target) : 0;
1289}
1290
1291bool Texture::isImmutable() const
1292{
1293 return mImmutable;
1294}
1295
jbauman@chromium.org68715282012-07-12 23:28:41 +00001296int Texture::getLodOffset()
1297{
1298 TextureStorage *texture = getStorage(false);
1299 return texture ? texture->getLodOffset() : 0;
1300}
1301
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001302GLint Texture::creationLevels(GLsizei width, GLsizei height) const
1303{
1304 if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture())
1305 {
1306 return 0; // Maximum number of levels
1307 }
1308 else
1309 {
1310 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1311 return 1;
1312 }
1313}
1314
1315GLint Texture::creationLevels(GLsizei size) const
1316{
1317 return creationLevels(size, size);
1318}
1319
jbauman@chromium.org6bc4a142012-09-06 21:28:30 +00001320int Texture::levelCount()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001321{
jbauman@chromium.org6bc4a142012-09-06 21:28:30 +00001322 return getBaseTexture() ? getBaseTexture()->GetLevelCount() - getLodOffset() : 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001323}
1324
1325Blit *Texture::getBlitter()
1326{
1327 Context *context = getContext();
1328 return context->getBlitter();
1329}
1330
1331bool Texture::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged)
1332{
1333 if (source && dest)
1334 {
1335 HRESULT result;
1336
1337 if (fromManaged)
1338 {
1339 result = D3DXLoadSurfaceFromSurface(dest, NULL, NULL, source, NULL, NULL, D3DX_FILTER_BOX, 0);
1340 }
1341 else
1342 {
1343 egl::Display *display = getDisplay();
1344 IDirect3DDevice9 *device = display->getDevice();
1345
1346 display->endScene();
1347 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1348 }
1349
1350 if (FAILED(result))
1351 {
1352 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1353 return false;
1354 }
1355 }
1356
1357 return true;
1358}
1359
1360TextureStorage2D::TextureStorage2D(IDirect3DTexture9 *surfaceTexture) : TextureStorage(D3DUSAGE_RENDERTARGET), mRenderTargetSerial(RenderbufferStorage::issueSerial())
1361{
1362 mTexture = surfaceTexture;
1363}
1364
1365TextureStorage2D::TextureStorage2D(int levels, D3DFORMAT format, DWORD usage, int width, int height)
1366 : TextureStorage(usage), mRenderTargetSerial(RenderbufferStorage::issueSerial())
1367{
1368 mTexture = NULL;
1369 // if the width or height is not positive this should be treated as an incomplete texture
1370 // we handle that here by skipping the d3d texture creation
1371 if (width > 0 && height > 0)
1372 {
1373 IDirect3DDevice9 *device = getDevice();
jbauman@chromium.org68715282012-07-12 23:28:41 +00001374 MakeValidSize(false, dx2es::IsCompressedD3DFormat(format), &width, &height, &mLodOffset);
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001375 HRESULT result = device->CreateTexture(width, height, levels ? levels + mLodOffset : 0, getUsage(), format, getPool(), &mTexture, NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001376
1377 if (FAILED(result))
1378 {
1379 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1380 error(GL_OUT_OF_MEMORY);
1381 }
1382 }
1383}
1384
1385TextureStorage2D::~TextureStorage2D()
1386{
1387 if (mTexture)
1388 {
1389 mTexture->Release();
1390 }
1391}
1392
1393// Increments refcount on surface.
1394// caller must Release() the returned surface
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001395IDirect3DSurface9 *TextureStorage2D::getSurfaceLevel(int level, bool dirty)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001396{
1397 IDirect3DSurface9 *surface = NULL;
1398
1399 if (mTexture)
1400 {
jbauman@chromium.org68715282012-07-12 23:28:41 +00001401 HRESULT result = mTexture->GetSurfaceLevel(level + mLodOffset, &surface);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001402 ASSERT(SUCCEEDED(result));
daniel@transgaming.com1ee986b2012-09-27 17:46:12 +00001403
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001404 // With managed textures the driver needs to be informed of updates to the lower mipmap levels
1405 if (level != 0 && isManaged() && dirty)
daniel@transgaming.com1ee986b2012-09-27 17:46:12 +00001406 {
1407 mTexture->AddDirtyRect(NULL);
1408 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001409 }
1410
1411 return surface;
1412}
1413
1414IDirect3DBaseTexture9 *TextureStorage2D::getBaseTexture() const
1415{
1416 return mTexture;
1417}
1418
1419unsigned int TextureStorage2D::getRenderTargetSerial(GLenum target) const
1420{
1421 return mRenderTargetSerial;
1422}
1423
1424Texture2D::Texture2D(GLuint id) : Texture(id)
1425{
1426 mTexStorage = NULL;
1427 mSurface = NULL;
1428 mColorbufferProxy = NULL;
1429 mProxyRefs = 0;
1430}
1431
1432Texture2D::~Texture2D()
1433{
1434 mColorbufferProxy = NULL;
1435
1436 delete mTexStorage;
1437 mTexStorage = NULL;
1438
1439 if (mSurface)
1440 {
1441 mSurface->setBoundTexture(NULL);
1442 mSurface = NULL;
1443 }
1444}
1445
1446// We need to maintain a count of references to renderbuffers acting as
1447// proxies for this texture, so that we do not attempt to use a pointer
1448// to a renderbuffer proxy which has been deleted.
1449void Texture2D::addProxyRef(const Renderbuffer *proxy)
1450{
1451 mProxyRefs++;
1452}
1453
1454void Texture2D::releaseProxy(const Renderbuffer *proxy)
1455{
1456 if (mProxyRefs > 0)
1457 mProxyRefs--;
1458
1459 if (mProxyRefs == 0)
1460 mColorbufferProxy = NULL;
1461}
1462
1463GLenum Texture2D::getTarget() const
1464{
1465 return GL_TEXTURE_2D;
1466}
1467
1468GLsizei Texture2D::getWidth(GLint level) const
1469{
1470 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1471 return mImageArray[level].getWidth();
1472 else
1473 return 0;
1474}
1475
1476GLsizei Texture2D::getHeight(GLint level) const
1477{
1478 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1479 return mImageArray[level].getHeight();
1480 else
1481 return 0;
1482}
1483
1484GLenum Texture2D::getInternalFormat(GLint level) const
1485{
1486 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001487 return mImageArray[level].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001488 else
1489 return GL_NONE;
1490}
1491
1492D3DFORMAT Texture2D::getD3DFormat(GLint level) const
1493{
1494 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1495 return mImageArray[level].getD3DFormat();
1496 else
1497 return D3DFMT_UNKNOWN;
1498}
1499
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001500void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001501{
1502 releaseTexImage();
1503
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001504 bool redefined = mImageArray[level].redefine(internalformat, width, height, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001505
1506 if (mTexStorage && redefined)
1507 {
1508 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1509 {
1510 mImageArray[i].markDirty();
1511 }
1512
1513 delete mTexStorage;
1514 mTexStorage = NULL;
1515 mDirtyImages = true;
1516 }
1517}
1518
1519void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1520{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001521 GLint internalformat = ConvertSizedInternalFormat(format, type);
1522 redefineImage(level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001523
1524 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
1525}
1526
1527void Texture2D::bindTexImage(egl::Surface *surface)
1528{
1529 releaseTexImage();
1530
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001531 GLint internalformat;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001532
1533 switch(surface->getFormat())
1534 {
1535 case D3DFMT_A8R8G8B8:
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001536 internalformat = GL_RGBA8_OES;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001537 break;
1538 case D3DFMT_X8R8G8B8:
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001539 internalformat = GL_RGB8_OES;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001540 break;
1541 default:
1542 UNIMPLEMENTED();
1543 return;
1544 }
1545
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001546 mImageArray[0].redefine(internalformat, surface->getWidth(), surface->getHeight(), true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001547
1548 delete mTexStorage;
1549 mTexStorage = new TextureStorage2D(surface->getOffscreenTexture());
1550
1551 mDirtyImages = true;
1552 mSurface = surface;
1553 mSurface->setBoundTexture(this);
1554}
1555
1556void Texture2D::releaseTexImage()
1557{
1558 if (mSurface)
1559 {
1560 mSurface->setBoundTexture(NULL);
1561 mSurface = NULL;
1562
1563 if (mTexStorage)
1564 {
1565 delete mTexStorage;
1566 mTexStorage = NULL;
1567 }
1568
1569 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1570 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001571 mImageArray[i].redefine(GL_RGBA8_OES, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001572 }
1573 }
1574}
1575
1576void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1577{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001578 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1579 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001580
1581 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
1582}
1583
1584void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1585{
1586 ASSERT(mImageArray[level].getSurface() != NULL);
1587
1588 if (level < levelCount())
1589 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001590 IDirect3DSurface9 *destLevel = mTexStorage->getSurfaceLevel(level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001591
1592 if (destLevel)
1593 {
1594 Image *image = &mImageArray[level];
1595 image->updateSurface(destLevel, xoffset, yoffset, width, height);
1596
1597 destLevel->Release();
1598 image->markClean();
1599 }
1600 }
1601}
1602
1603void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1604{
1605 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1606 {
1607 commitRect(level, xoffset, yoffset, width, height);
1608 }
1609}
1610
1611void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1612{
1613 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1614 {
1615 commitRect(level, xoffset, yoffset, width, height);
1616 }
1617}
1618
1619void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1620{
1621 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1622
1623 if (!renderTarget)
1624 {
1625 ERR("Failed to retrieve the render target.");
1626 return error(GL_OUT_OF_MEMORY);
1627 }
1628
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001629 GLint internalformat = ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1630 redefineImage(level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001631
1632 if (!mImageArray[level].isRenderableFormat())
1633 {
1634 mImageArray[level].copy(0, 0, x, y, width, height, renderTarget);
1635 mDirtyImages = true;
1636 }
1637 else
1638 {
1639 if (!mTexStorage || !mTexStorage->isRenderTarget())
1640 {
1641 convertToRenderTarget();
1642 }
1643
1644 mImageArray[level].markClean();
1645
1646 if (width != 0 && height != 0 && level < levelCount())
1647 {
1648 RECT sourceRect;
1649 sourceRect.left = x;
1650 sourceRect.right = x + width;
1651 sourceRect.top = y;
1652 sourceRect.bottom = y + height;
1653
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001654 IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001655
1656 if (dest)
1657 {
1658 getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest);
1659 dest->Release();
1660 }
1661 }
1662 }
1663
1664 renderTarget->Release();
1665}
1666
1667void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1668{
1669 if (xoffset + width > mImageArray[level].getWidth() || yoffset + height > mImageArray[level].getHeight())
1670 {
1671 return error(GL_INVALID_VALUE);
1672 }
1673
1674 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1675
1676 if (!renderTarget)
1677 {
1678 ERR("Failed to retrieve the render target.");
1679 return error(GL_OUT_OF_MEMORY);
1680 }
1681
1682 if (!mImageArray[level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
1683 {
1684 mImageArray[level].copy(xoffset, yoffset, x, y, width, height, renderTarget);
1685 mDirtyImages = true;
1686 }
1687 else
1688 {
1689 if (!mTexStorage || !mTexStorage->isRenderTarget())
1690 {
1691 convertToRenderTarget();
1692 }
1693
1694 updateTexture();
1695
1696 if (level < levelCount())
1697 {
1698 RECT sourceRect;
1699 sourceRect.left = x;
1700 sourceRect.right = x + width;
1701 sourceRect.top = y;
1702 sourceRect.bottom = y + height;
1703
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001704 IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001705
1706 if (dest)
1707 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001708 getBlitter()->copy(renderTarget, sourceRect,
1709 gl::ExtractFormat(mImageArray[0].getInternalFormat()),
1710 xoffset, yoffset, dest);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001711 dest->Release();
1712 }
1713 }
1714 }
1715
1716 renderTarget->Release();
1717}
1718
1719void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
1720{
daniel@transgaming.com6b1a0a02012-10-17 18:22:47 +00001721 D3DFORMAT d3dfmt = ConvertTextureInternalFormat(internalformat);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001722 DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false);
1723
1724 delete mTexStorage;
1725 mTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height);
1726 mImmutable = true;
1727
1728 for (int level = 0; level < levels; level++)
1729 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001730 mImageArray[level].redefine(internalformat, width, height, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001731 width = std::max(1, width >> 1);
1732 height = std::max(1, height >> 1);
1733 }
1734
1735 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1736 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001737 mImageArray[level].redefine(GL_NONE, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001738 }
1739
1740 if (mTexStorage->isManaged())
1741 {
1742 int levels = levelCount();
1743
1744 for (int level = 0; level < levels; level++)
1745 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001746 IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001747 mImageArray[level].setManagedSurface(surface);
1748 }
1749 }
1750}
1751
1752// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
1753bool Texture2D::isSamplerComplete() const
1754{
1755 GLsizei width = mImageArray[0].getWidth();
1756 GLsizei height = mImageArray[0].getHeight();
1757
1758 if (width <= 0 || height <= 0)
1759 {
1760 return false;
1761 }
1762
1763 bool mipmapping = false;
1764
1765 switch (mMinFilter)
1766 {
1767 case GL_NEAREST:
1768 case GL_LINEAR:
1769 mipmapping = false;
1770 break;
1771 case GL_NEAREST_MIPMAP_NEAREST:
1772 case GL_LINEAR_MIPMAP_NEAREST:
1773 case GL_NEAREST_MIPMAP_LINEAR:
1774 case GL_LINEAR_MIPMAP_LINEAR:
1775 mipmapping = true;
1776 break;
1777 default: UNREACHABLE();
1778 }
1779
daniel@transgaming.com6b1a0a02012-10-17 18:22:47 +00001780 if ((IsFloat32Format(getInternalFormat(0)) && !getContext()->supportsFloat32LinearFilter()) ||
1781 (IsFloat16Format(getInternalFormat(0)) && !getContext()->supportsFloat16LinearFilter()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001782 {
1783 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1784 {
1785 return false;
1786 }
1787 }
1788
1789 bool npotSupport = getContext()->supportsNonPower2Texture();
1790
1791 if (!npotSupport)
1792 {
1793 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
1794 (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1795 {
1796 return false;
1797 }
1798 }
1799
1800 if (mipmapping)
1801 {
1802 if (!npotSupport)
1803 {
1804 if (!isPow2(width) || !isPow2(height))
1805 {
1806 return false;
1807 }
1808 }
1809
1810 if (!isMipmapComplete())
1811 {
1812 return false;
1813 }
1814 }
1815
1816 return true;
1817}
1818
1819// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1820bool Texture2D::isMipmapComplete() const
1821{
1822 if (isImmutable())
1823 {
1824 return true;
1825 }
1826
1827 GLsizei width = mImageArray[0].getWidth();
1828 GLsizei height = mImageArray[0].getHeight();
1829
1830 if (width <= 0 || height <= 0)
1831 {
1832 return false;
1833 }
1834
1835 int q = log2(std::max(width, height));
1836
1837 for (int level = 1; level <= q; level++)
1838 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001839 if (mImageArray[level].getInternalFormat() != mImageArray[0].getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001840 {
1841 return false;
1842 }
1843
1844 if (mImageArray[level].getWidth() != std::max(1, width >> level))
1845 {
1846 return false;
1847 }
1848
1849 if (mImageArray[level].getHeight() != std::max(1, height >> level))
1850 {
1851 return false;
1852 }
1853 }
1854
1855 return true;
1856}
1857
1858bool Texture2D::isCompressed(GLint level) const
1859{
1860 return IsCompressed(getInternalFormat(level));
1861}
1862
1863bool Texture2D::isDepth(GLint level) const
1864{
1865 return IsDepthTexture(getInternalFormat(level));
1866}
1867
1868IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1869{
1870 return mTexStorage ? mTexStorage->getBaseTexture() : NULL;
1871}
1872
1873// Constructs a Direct3D 9 texture resource from the texture images
1874void Texture2D::createTexture()
1875{
1876 GLsizei width = mImageArray[0].getWidth();
1877 GLsizei height = mImageArray[0].getHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001878
1879 if (!(width > 0 && height > 0))
1880 return; // do not attempt to create d3d textures for nonexistant data
1881
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001882 GLint levels = creationLevels(width, height);
1883 D3DFORMAT d3dfmt = mImageArray[0].getD3DFormat();
1884 DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false);
1885
1886 delete mTexStorage;
1887 mTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height);
1888
1889 if (mTexStorage->isManaged())
1890 {
1891 int levels = levelCount();
1892
1893 for (int level = 0; level < levels; level++)
1894 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001895 IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001896 mImageArray[level].setManagedSurface(surface);
1897 }
1898 }
1899
1900 mDirtyImages = true;
1901}
1902
1903void Texture2D::updateTexture()
1904{
1905 int levels = levelCount();
1906
1907 for (int level = 0; level < levels; level++)
1908 {
1909 Image *image = &mImageArray[level];
1910
1911 if (image->isDirty())
1912 {
1913 commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight());
1914 }
1915 }
1916}
1917
1918void Texture2D::convertToRenderTarget()
1919{
1920 TextureStorage2D *newTexStorage = NULL;
1921
1922 if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0)
1923 {
1924 GLsizei width = mImageArray[0].getWidth();
1925 GLsizei height = mImageArray[0].getHeight();
1926 GLint levels = creationLevels(width, height);
1927 D3DFORMAT d3dfmt = mImageArray[0].getD3DFormat();
1928 DWORD d3dusage = GetTextureUsage(d3dfmt, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true);
1929
1930 newTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height);
1931
1932 if (mTexStorage != NULL)
1933 {
1934 int levels = levelCount();
1935 for (int i = 0; i < levels; i++)
1936 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001937 IDirect3DSurface9 *source = mTexStorage->getSurfaceLevel(i, false);
1938 IDirect3DSurface9 *dest = newTexStorage->getSurfaceLevel(i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001939
1940 if (!copyToRenderTarget(dest, source, mTexStorage->isManaged()))
1941 {
1942 delete newTexStorage;
1943 if (source) source->Release();
1944 if (dest) dest->Release();
1945 return error(GL_OUT_OF_MEMORY);
1946 }
1947
1948 if (source) source->Release();
1949 if (dest) dest->Release();
1950 }
1951 }
1952 }
1953
1954 delete mTexStorage;
1955 mTexStorage = newTexStorage;
1956
1957 mDirtyImages = true;
1958}
1959
1960void Texture2D::generateMipmaps()
1961{
1962 if (!getContext()->supportsNonPower2Texture())
1963 {
1964 if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight()))
1965 {
1966 return error(GL_INVALID_OPERATION);
1967 }
1968 }
1969
1970 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1971 unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight()));
1972 for (unsigned int i = 1; i <= q; i++)
1973 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001974 redefineImage(i, mImageArray[0].getInternalFormat(),
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001975 std::max(mImageArray[0].getWidth() >> i, 1),
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001976 std::max(mImageArray[0].getHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001977 }
1978
1979 if (mTexStorage && mTexStorage->isRenderTarget())
1980 {
1981 for (unsigned int i = 1; i <= q; i++)
1982 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001983 IDirect3DSurface9 *upper = mTexStorage->getSurfaceLevel(i - 1, false);
1984 IDirect3DSurface9 *lower = mTexStorage->getSurfaceLevel(i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001985
1986 if (upper != NULL && lower != NULL)
1987 {
1988 getBlitter()->boxFilter(upper, lower);
1989 }
1990
1991 if (upper != NULL) upper->Release();
1992 if (lower != NULL) lower->Release();
1993
1994 mImageArray[i].markClean();
1995 }
1996 }
1997 else
1998 {
1999 for (unsigned int i = 1; i <= q; i++)
2000 {
2001 if (mImageArray[i].getSurface() == NULL)
2002 {
2003 return error(GL_OUT_OF_MEMORY);
2004 }
2005
2006 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].getSurface(), NULL, NULL, mImageArray[i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0)))
2007 {
2008 ERR(" failed to load filter %d to %d.", i - 1, i);
2009 }
2010
2011 mImageArray[i].markDirty();
2012 }
2013 }
2014}
2015
2016Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
2017{
2018 if (target != GL_TEXTURE_2D)
2019 {
2020 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2021 }
2022
2023 if (mColorbufferProxy == NULL)
2024 {
2025 mColorbufferProxy = new Renderbuffer(id(), new RenderbufferTexture2D(this, target));
2026 }
2027
2028 return mColorbufferProxy;
2029}
2030
2031// Increments refcount on surface.
2032// caller must Release() the returned surface
2033IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
2034{
2035 ASSERT(target == GL_TEXTURE_2D);
2036
2037 // ensure the underlying texture is created
2038 if (getStorage(true) == NULL)
2039 {
2040 return NULL;
2041 }
2042
2043 updateTexture();
2044
2045 // ensure this is NOT a depth texture
2046 if (isDepth(0))
2047 {
2048 return NULL;
2049 }
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00002050 return mTexStorage->getSurfaceLevel(0, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002051}
2052
2053// Increments refcount on surface.
2054// caller must Release() the returned surface
2055IDirect3DSurface9 *Texture2D::getDepthStencil(GLenum target)
2056{
2057 ASSERT(target == GL_TEXTURE_2D);
2058
2059 // ensure the underlying texture is created
2060 if (getStorage(true) == NULL)
2061 {
2062 return NULL;
2063 }
2064
2065 updateTexture();
2066
2067 // ensure this is actually a depth texture
2068 if (!isDepth(0))
2069 {
2070 return NULL;
2071 }
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00002072 return mTexStorage->getSurfaceLevel(0, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002073}
2074
2075TextureStorage *Texture2D::getStorage(bool renderTarget)
2076{
2077 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2078 {
2079 if (renderTarget)
2080 {
2081 convertToRenderTarget();
2082 }
2083 else
2084 {
2085 createTexture();
2086 }
2087 }
2088
2089 return mTexStorage;
2090}
2091
2092TextureStorageCubeMap::TextureStorageCubeMap(int levels, D3DFORMAT format, DWORD usage, int size)
2093 : TextureStorage(usage), mFirstRenderTargetSerial(RenderbufferStorage::issueCubeSerials())
2094{
2095 mTexture = NULL;
2096 // if the size is not positive this should be treated as an incomplete texture
2097 // we handle that here by skipping the d3d texture creation
2098 if (size > 0)
2099 {
2100 IDirect3DDevice9 *device = getDevice();
jbauman@chromium.org68715282012-07-12 23:28:41 +00002101 int height = size;
2102 MakeValidSize(false, dx2es::IsCompressedD3DFormat(format), &size, &height, &mLodOffset);
sminns@adobe.comce1189b2012-09-18 20:06:35 +00002103 HRESULT result = device->CreateCubeTexture(size, levels ? levels + mLodOffset : 0, getUsage(), format, getPool(), &mTexture, NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002104
2105 if (FAILED(result))
2106 {
2107 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2108 error(GL_OUT_OF_MEMORY);
2109 }
2110 }
2111}
2112
2113TextureStorageCubeMap::~TextureStorageCubeMap()
2114{
2115 if (mTexture)
2116 {
2117 mTexture->Release();
2118 }
2119}
2120
2121// Increments refcount on surface.
2122// caller must Release() the returned surface
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00002123IDirect3DSurface9 *TextureStorageCubeMap::getCubeMapSurface(GLenum faceTarget, int level, bool dirty)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002124{
2125 IDirect3DSurface9 *surface = NULL;
2126
2127 if (mTexture)
2128 {
daniel@transgaming.com1ee986b2012-09-27 17:46:12 +00002129 D3DCUBEMAP_FACES face = es2dx::ConvertCubeFace(faceTarget);
2130 HRESULT result = mTexture->GetCubeMapSurface(face, level + mLodOffset, &surface);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002131 ASSERT(SUCCEEDED(result));
daniel@transgaming.com1ee986b2012-09-27 17:46:12 +00002132
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00002133 // With managed textures the driver needs to be informed of updates to the lower mipmap levels
2134 if (level != 0 && isManaged() && dirty)
daniel@transgaming.com1ee986b2012-09-27 17:46:12 +00002135 {
2136 mTexture->AddDirtyRect(face, NULL);
2137 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002138 }
2139
2140 return surface;
2141}
2142
2143IDirect3DBaseTexture9 *TextureStorageCubeMap::getBaseTexture() const
2144{
2145 return mTexture;
2146}
2147
2148unsigned int TextureStorageCubeMap::getRenderTargetSerial(GLenum target) const
2149{
2150 return mFirstRenderTargetSerial + TextureCubeMap::faceIndex(target);
2151}
2152
2153TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
2154{
2155 mTexStorage = NULL;
2156 for (int i = 0; i < 6; i++)
2157 {
2158 mFaceProxies[i] = NULL;
2159 mFaceProxyRefs[i] = 0;
2160 }
2161}
2162
2163TextureCubeMap::~TextureCubeMap()
2164{
2165 for (int i = 0; i < 6; i++)
2166 {
2167 mFaceProxies[i] = NULL;
2168 }
2169
2170 delete mTexStorage;
2171 mTexStorage = NULL;
2172}
2173
2174// We need to maintain a count of references to renderbuffers acting as
2175// proxies for this texture, so that the texture is not deleted while
2176// proxy references still exist. If the reference count drops to zero,
2177// we set our proxy pointer NULL, so that a new attempt at referencing
2178// will cause recreation.
2179void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
2180{
2181 for (int i = 0; i < 6; i++)
2182 {
2183 if (mFaceProxies[i] == proxy)
2184 mFaceProxyRefs[i]++;
2185 }
2186}
2187
2188void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
2189{
2190 for (int i = 0; i < 6; i++)
2191 {
2192 if (mFaceProxies[i] == proxy)
2193 {
2194 if (mFaceProxyRefs[i] > 0)
2195 mFaceProxyRefs[i]--;
2196
2197 if (mFaceProxyRefs[i] == 0)
2198 mFaceProxies[i] = NULL;
2199 }
2200 }
2201}
2202
2203GLenum TextureCubeMap::getTarget() const
2204{
2205 return GL_TEXTURE_CUBE_MAP;
2206}
2207
2208GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
2209{
2210 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2211 return mImageArray[faceIndex(target)][level].getWidth();
2212 else
2213 return 0;
2214}
2215
2216GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
2217{
2218 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2219 return mImageArray[faceIndex(target)][level].getHeight();
2220 else
2221 return 0;
2222}
2223
2224GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
2225{
2226 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00002227 return mImageArray[faceIndex(target)][level].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002228 else
2229 return GL_NONE;
2230}
2231
2232D3DFORMAT TextureCubeMap::getD3DFormat(GLenum target, GLint level) const
2233{
2234 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2235 return mImageArray[faceIndex(target)][level].getD3DFormat();
2236 else
2237 return D3DFMT_UNKNOWN;
2238}
2239
2240void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2241{
2242 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
2243}
2244
2245void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2246{
2247 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
2248}
2249
2250void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2251{
2252 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
2253}
2254
2255void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2256{
2257 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
2258}
2259
2260void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2261{
2262 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
2263}
2264
2265void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2266{
2267 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
2268}
2269
2270void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
2271{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00002272 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2273 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002274
2275 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
2276}
2277
2278void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
2279{
2280 ASSERT(mImageArray[face][level].getSurface() != NULL);
2281
2282 if (level < levelCount())
2283 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00002284 IDirect3DSurface9 *destLevel = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002285 ASSERT(destLevel != NULL);
2286
2287 if (destLevel != NULL)
2288 {
2289 Image *image = &mImageArray[face][level];
2290 image->updateSurface(destLevel, xoffset, yoffset, width, height);
2291
2292 destLevel->Release();
2293 image->markClean();
2294 }
2295 }
2296}
2297
2298void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2299{
2300 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
2301 {
2302 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
2303 }
2304}
2305
2306void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
2307{
2308 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
2309 {
2310 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
2311 }
2312}
2313
2314// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
2315bool TextureCubeMap::isSamplerComplete() const
2316{
2317 int size = mImageArray[0][0].getWidth();
2318
2319 bool mipmapping;
2320
2321 switch (mMinFilter)
2322 {
2323 case GL_NEAREST:
2324 case GL_LINEAR:
2325 mipmapping = false;
2326 break;
2327 case GL_NEAREST_MIPMAP_NEAREST:
2328 case GL_LINEAR_MIPMAP_NEAREST:
2329 case GL_NEAREST_MIPMAP_LINEAR:
2330 case GL_LINEAR_MIPMAP_LINEAR:
2331 mipmapping = true;
2332 break;
2333 default:
2334 UNREACHABLE();
2335 return false;
2336 }
2337
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00002338 if ((gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) ||
2339 (gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES) && !getContext()->supportsFloat16LinearFilter()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002340 {
2341 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
2342 {
2343 return false;
2344 }
2345 }
2346
2347 if (!isPow2(size) && !getContext()->supportsNonPower2Texture())
2348 {
2349 if (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE || mipmapping)
2350 {
2351 return false;
2352 }
2353 }
2354
2355 if (!mipmapping)
2356 {
2357 if (!isCubeComplete())
2358 {
2359 return false;
2360 }
2361 }
2362 else
2363 {
2364 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
2365 {
2366 return false;
2367 }
2368 }
2369
2370 return true;
2371}
2372
2373// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
2374bool TextureCubeMap::isCubeComplete() const
2375{
2376 if (mImageArray[0][0].getWidth() <= 0 || mImageArray[0][0].getHeight() != mImageArray[0][0].getWidth())
2377 {
2378 return false;
2379 }
2380
2381 for (unsigned int face = 1; face < 6; face++)
2382 {
2383 if (mImageArray[face][0].getWidth() != mImageArray[0][0].getWidth() ||
2384 mImageArray[face][0].getWidth() != mImageArray[0][0].getHeight() ||
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00002385 mImageArray[face][0].getInternalFormat() != mImageArray[0][0].getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002386 {
2387 return false;
2388 }
2389 }
2390
2391 return true;
2392}
2393
2394bool TextureCubeMap::isMipmapCubeComplete() const
2395{
2396 if (isImmutable())
2397 {
2398 return true;
2399 }
2400
2401 if (!isCubeComplete())
2402 {
2403 return false;
2404 }
2405
2406 GLsizei size = mImageArray[0][0].getWidth();
2407
2408 int q = log2(size);
2409
2410 for (int face = 0; face < 6; face++)
2411 {
2412 for (int level = 1; level <= q; level++)
2413 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00002414 if (mImageArray[face][level].getInternalFormat() != mImageArray[0][0].getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002415 {
2416 return false;
2417 }
2418
2419 if (mImageArray[face][level].getWidth() != std::max(1, size >> level))
2420 {
2421 return false;
2422 }
2423 }
2424 }
2425
2426 return true;
2427}
2428
2429bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
2430{
2431 return IsCompressed(getInternalFormat(target, level));
2432}
2433
2434IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
2435{
2436 return mTexStorage ? mTexStorage->getBaseTexture() : NULL;
2437}
2438
2439// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
2440void TextureCubeMap::createTexture()
2441{
2442 GLsizei size = mImageArray[0][0].getWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00002443
2444 if (!(size > 0))
2445 return; // do not attempt to create d3d textures for nonexistant data
2446
sminns@adobe.comce1189b2012-09-18 20:06:35 +00002447 GLint levels = creationLevels(size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002448 D3DFORMAT d3dfmt = mImageArray[0][0].getD3DFormat();
2449 DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false);
2450
2451 delete mTexStorage;
2452 mTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size);
2453
2454 if (mTexStorage->isManaged())
2455 {
2456 int levels = levelCount();
2457
2458 for (int face = 0; face < 6; face++)
2459 {
2460 for (int level = 0; level < levels; level++)
2461 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00002462 IDirect3DSurface9 *surface = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002463 mImageArray[face][level].setManagedSurface(surface);
2464 }
2465 }
2466 }
2467
2468 mDirtyImages = true;
2469}
2470
2471void TextureCubeMap::updateTexture()
2472{
2473 for (int face = 0; face < 6; face++)
2474 {
2475 int levels = levelCount();
2476 for (int level = 0; level < levels; level++)
2477 {
2478 Image *image = &mImageArray[face][level];
2479
2480 if (image->isDirty())
2481 {
2482 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
2483 }
2484 }
2485 }
2486}
2487
2488void TextureCubeMap::convertToRenderTarget()
2489{
2490 TextureStorageCubeMap *newTexStorage = NULL;
2491
2492 if (mImageArray[0][0].getWidth() != 0)
2493 {
2494 GLsizei size = mImageArray[0][0].getWidth();
sminns@adobe.comce1189b2012-09-18 20:06:35 +00002495 GLint levels = creationLevels(size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002496 D3DFORMAT d3dfmt = mImageArray[0][0].getD3DFormat();
2497 DWORD d3dusage = GetTextureUsage(d3dfmt, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true);
2498
2499 newTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size);
2500
2501 if (mTexStorage != NULL)
2502 {
2503 int levels = levelCount();
2504 for (int f = 0; f < 6; f++)
2505 {
2506 for (int i = 0; i < levels; i++)
2507 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00002508 IDirect3DSurface9 *source = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false);
2509 IDirect3DSurface9 *dest = newTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002510
2511 if (!copyToRenderTarget(dest, source, mTexStorage->isManaged()))
2512 {
2513 delete newTexStorage;
2514 if (source) source->Release();
2515 if (dest) dest->Release();
2516 return error(GL_OUT_OF_MEMORY);
2517 }
2518
2519 if (source) source->Release();
2520 if (dest) dest->Release();
2521 }
2522 }
2523 }
2524 }
2525
2526 delete mTexStorage;
2527 mTexStorage = newTexStorage;
2528
2529 mDirtyImages = true;
2530}
2531
2532void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2533{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00002534 GLint internalformat = ConvertSizedInternalFormat(format, type);
2535 redefineImage(faceIndex, level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002536
2537 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
2538}
2539
2540unsigned int TextureCubeMap::faceIndex(GLenum face)
2541{
2542 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2543 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2544 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2545 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2546 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2547
2548 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2549}
2550
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00002551void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002552{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00002553 bool redefined = mImageArray[face][level].redefine(internalformat, width, height, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002554
2555 if (mTexStorage && redefined)
2556 {
2557 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2558 {
2559 for (int f = 0; f < 6; f++)
2560 {
2561 mImageArray[f][i].markDirty();
2562 }
2563 }
2564
2565 delete mTexStorage;
2566 mTexStorage = NULL;
2567
2568 mDirtyImages = true;
2569 }
2570}
2571
2572void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2573{
2574 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2575
2576 if (!renderTarget)
2577 {
2578 ERR("Failed to retrieve the render target.");
2579 return error(GL_OUT_OF_MEMORY);
2580 }
2581
2582 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00002583 GLint internalformat = gl::ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
2584 redefineImage(faceindex, level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002585
2586 if (!mImageArray[faceindex][level].isRenderableFormat())
2587 {
2588 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
2589 mDirtyImages = true;
2590 }
2591 else
2592 {
2593 if (!mTexStorage || !mTexStorage->isRenderTarget())
2594 {
2595 convertToRenderTarget();
2596 }
2597
2598 mImageArray[faceindex][level].markClean();
2599
2600 ASSERT(width == height);
2601
2602 if (width > 0 && level < levelCount())
2603 {
2604 RECT sourceRect;
2605 sourceRect.left = x;
2606 sourceRect.right = x + width;
2607 sourceRect.top = y;
2608 sourceRect.bottom = y + height;
2609
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00002610 IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002611
2612 if (dest)
2613 {
2614 getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest);
2615 dest->Release();
2616 }
2617 }
2618 }
2619
2620 renderTarget->Release();
2621}
2622
2623void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2624{
2625 GLsizei size = mImageArray[faceIndex(target)][level].getWidth();
2626
2627 if (xoffset + width > size || yoffset + height > size)
2628 {
2629 return error(GL_INVALID_VALUE);
2630 }
2631
2632 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2633
2634 if (!renderTarget)
2635 {
2636 ERR("Failed to retrieve the render target.");
2637 return error(GL_OUT_OF_MEMORY);
2638 }
2639
2640 unsigned int faceindex = faceIndex(target);
2641
2642 if (!mImageArray[faceindex][level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
2643 {
2644 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
2645 mDirtyImages = true;
2646 }
2647 else
2648 {
2649 if (!mTexStorage || !mTexStorage->isRenderTarget())
2650 {
2651 convertToRenderTarget();
2652 }
2653
2654 updateTexture();
2655
2656 if (level < levelCount())
2657 {
2658 RECT sourceRect;
2659 sourceRect.left = x;
2660 sourceRect.right = x + width;
2661 sourceRect.top = y;
2662 sourceRect.bottom = y + height;
2663
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00002664 IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002665
2666 if (dest)
2667 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00002668 getBlitter()->copy(renderTarget, sourceRect, gl::ExtractFormat(mImageArray[0][0].getInternalFormat()), xoffset, yoffset, dest);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002669 dest->Release();
2670 }
2671 }
2672 }
2673
2674 renderTarget->Release();
2675}
2676
2677void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
2678{
daniel@transgaming.com6b1a0a02012-10-17 18:22:47 +00002679 D3DFORMAT d3dfmt = ConvertTextureInternalFormat(internalformat);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002680 DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false);
2681
2682 delete mTexStorage;
2683 mTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size);
2684 mImmutable = true;
2685
2686 for (int level = 0; level < levels; level++)
2687 {
2688 for (int face = 0; face < 6; face++)
2689 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00002690 mImageArray[face][level].redefine(internalformat, size, size, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002691 size = std::max(1, size >> 1);
2692 }
2693 }
2694
2695 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2696 {
2697 for (int face = 0; face < 6; face++)
2698 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00002699 mImageArray[face][level].redefine(GL_NONE, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002700 }
2701 }
2702
2703 if (mTexStorage->isManaged())
2704 {
2705 int levels = levelCount();
2706
2707 for (int face = 0; face < 6; face++)
2708 {
2709 for (int level = 0; level < levels; level++)
2710 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00002711 IDirect3DSurface9 *surface = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002712 mImageArray[face][level].setManagedSurface(surface);
2713 }
2714 }
2715 }
2716}
2717
2718void TextureCubeMap::generateMipmaps()
2719{
2720 if (!isCubeComplete())
2721 {
2722 return error(GL_INVALID_OPERATION);
2723 }
2724
2725 if (!getContext()->supportsNonPower2Texture())
2726 {
2727 if (!isPow2(mImageArray[0][0].getWidth()))
2728 {
2729 return error(GL_INVALID_OPERATION);
2730 }
2731 }
2732
2733 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2734 unsigned int q = log2(mImageArray[0][0].getWidth());
2735 for (unsigned int f = 0; f < 6; f++)
2736 {
2737 for (unsigned int i = 1; i <= q; i++)
2738 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00002739 redefineImage(f, i, mImageArray[f][0].getInternalFormat(),
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002740 std::max(mImageArray[f][0].getWidth() >> i, 1),
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00002741 std::max(mImageArray[f][0].getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002742 }
2743 }
2744
2745 if (mTexStorage && mTexStorage->isRenderTarget())
2746 {
2747 for (unsigned int f = 0; f < 6; f++)
2748 {
2749 for (unsigned int i = 1; i <= q; i++)
2750 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00002751 IDirect3DSurface9 *upper = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i - 1, false);
2752 IDirect3DSurface9 *lower = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002753
2754 if (upper != NULL && lower != NULL)
2755 {
2756 getBlitter()->boxFilter(upper, lower);
2757 }
2758
2759 if (upper != NULL) upper->Release();
2760 if (lower != NULL) lower->Release();
2761
2762 mImageArray[f][i].markClean();
2763 }
2764 }
2765 }
2766 else
2767 {
2768 for (unsigned int f = 0; f < 6; f++)
2769 {
2770 for (unsigned int i = 1; i <= q; i++)
2771 {
2772 if (mImageArray[f][i].getSurface() == NULL)
2773 {
2774 return error(GL_OUT_OF_MEMORY);
2775 }
2776
2777 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].getSurface(), NULL, NULL, mImageArray[f][i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0)))
2778 {
2779 ERR(" failed to load filter %d to %d.", i - 1, i);
2780 }
2781
2782 mImageArray[f][i].markDirty();
2783 }
2784 }
2785 }
2786}
2787
2788Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2789{
2790 if (!IsCubemapTextureTarget(target))
2791 {
2792 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2793 }
2794
2795 unsigned int face = faceIndex(target);
2796
2797 if (mFaceProxies[face] == NULL)
2798 {
2799 mFaceProxies[face] = new Renderbuffer(id(), new RenderbufferTextureCubeMap(this, target));
2800 }
2801
2802 return mFaceProxies[face];
2803}
2804
2805// Increments refcount on surface.
2806// caller must Release() the returned surface
2807IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2808{
2809 ASSERT(IsCubemapTextureTarget(target));
2810
2811 // ensure the underlying texture is created
2812 if (getStorage(true) == NULL)
2813 {
2814 return NULL;
2815 }
2816
2817 updateTexture();
2818
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00002819 return mTexStorage->getCubeMapSurface(target, 0, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002820}
2821
2822TextureStorage *TextureCubeMap::getStorage(bool renderTarget)
2823{
2824 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2825 {
2826 if (renderTarget)
2827 {
2828 convertToRenderTarget();
2829 }
2830 else
2831 {
2832 createTexture();
2833 }
2834 }
2835
2836 return mTexStorage;
2837}
2838
2839}