blob: 612d795e1b36dcd8ccedd04568d1dd8c6fb63c3e [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
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
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000011#include "libGLESv2/Texture.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000012
daniel@transgaming.com16973022010-03-11 19:22:19 +000013#include <algorithm>
14
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000015#include "common/debug.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000016
17#include "libGLESv2/main.h"
18#include "libGLESv2/mathutil.h"
19#include "libGLESv2/utilities.h"
20#include "libGLESv2/Blit.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000021
22namespace gl
23{
daniel@transgaming.com842f7a42010-03-21 04:31:03 +000024
25Texture::Image::Image()
daniel@transgaming.com01868132010-08-24 19:21:17 +000026 : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +000027{
28}
29
30Texture::Image::~Image()
31{
32 if (surface) surface->Release();
33}
34
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000035Texture::Texture(GLuint id) : RefCountObject(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000036{
37 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
38 mMagFilter = GL_LINEAR;
39 mWrapS = GL_REPEAT;
40 mWrapT = GL_REPEAT;
daniel@transgaming.com29d27002010-03-11 19:41:22 +000041
daniel@transgaming.com31273552010-08-04 13:42:44 +000042 mWidth = 0;
43 mHeight = 0;
44
daniel@transgaming.com00c75962010-03-11 20:36:15 +000045 mDirtyMetaData = true;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000046 mDirty = true;
daniel@transgaming.com93a81472010-04-20 18:52:58 +000047 mIsRenderable = false;
daniel@transgaming.com0a311a42010-05-17 09:58:33 +000048 mBaseTexture = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000049}
50
51Texture::~Texture()
52{
53}
54
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000055Blit *Texture::getBlitter()
56{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000057 Context *context = getContext();
58 return context->getBlitter();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000059}
60
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000061// Returns true on successful filter state update (valid enum parameter)
62bool Texture::setMinFilter(GLenum filter)
63{
64 switch (filter)
65 {
66 case GL_NEAREST:
67 case GL_LINEAR:
68 case GL_NEAREST_MIPMAP_NEAREST:
69 case GL_LINEAR_MIPMAP_NEAREST:
70 case GL_NEAREST_MIPMAP_LINEAR:
71 case GL_LINEAR_MIPMAP_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000072 {
73 if (mMinFilter != filter)
74 {
75 mMinFilter = filter;
76 mDirty = true;
77 }
78 return true;
79 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000080 default:
81 return false;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +000082 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000083}
84
85// Returns true on successful filter state update (valid enum parameter)
86bool Texture::setMagFilter(GLenum filter)
87{
88 switch (filter)
89 {
90 case GL_NEAREST:
91 case GL_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000092 {
93 if (mMagFilter != filter)
94 {
95 mMagFilter = filter;
96 mDirty = true;
97 }
98 return true;
99 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000100 default:
101 return false;
102 }
103}
104
105// Returns true on successful wrap state update (valid enum parameter)
106bool Texture::setWrapS(GLenum wrap)
107{
108 switch (wrap)
109 {
110 case GL_REPEAT:
111 case GL_CLAMP_TO_EDGE:
112 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000113 {
114 if (mWrapS != wrap)
115 {
116 mWrapS = wrap;
117 mDirty = true;
118 }
119 return true;
120 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000121 default:
122 return false;
123 }
124}
125
126// Returns true on successful wrap state update (valid enum parameter)
127bool Texture::setWrapT(GLenum wrap)
128{
129 switch (wrap)
130 {
131 case GL_REPEAT:
132 case GL_CLAMP_TO_EDGE:
133 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000134 {
135 if (mWrapT != wrap)
136 {
137 mWrapT = wrap;
138 mDirty = true;
139 }
140 return true;
141 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000142 default:
143 return false;
144 }
145}
146
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000147GLenum Texture::getMinFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000148{
149 return mMinFilter;
150}
151
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000152GLenum Texture::getMagFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000153{
154 return mMagFilter;
155}
156
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000157GLenum Texture::getWrapS() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000158{
159 return mWrapS;
160}
161
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000162GLenum Texture::getWrapT() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000163{
164 return mWrapT;
165}
166
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000167GLuint Texture::getWidth() const
168{
169 return mWidth;
170}
171
172GLuint Texture::getHeight() const
173{
174 return mHeight;
175}
176
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000177// Selects an internal Direct3D 9 format for storing an Image
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000178D3DFORMAT Texture::selectFormat(GLenum format)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000179{
daniel@transgaming.com01868132010-08-24 19:21:17 +0000180 if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
181 format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
182 {
183 return D3DFMT_DXT1;
184 }
185 else
186 {
187 return D3DFMT_A8R8G8B8;
188 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000189}
190
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000191int Texture::imagePitch(const Image &img) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000192{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000193 return img.width * 4;
194}
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000195
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000196// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
197// into the BGRA8 pixel rectangle at output with outputPitch bytes in between each line.
198void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000199 GLint unpackAlignment, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000200{
daniel@transgaming.com713914b2010-05-04 03:35:17 +0000201 GLsizei inputPitch = ComputePitch(width, format, type, unpackAlignment);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000202
203 for (int y = 0; y < height; y++)
204 {
205 const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch;
206 const unsigned short *source16 = reinterpret_cast<const unsigned short*>(source);
207 unsigned char *dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
208
daniel@transgaming.coma9198d92010-08-08 04:49:56 +0000209 // fast path for EXT_texture_format_BGRA8888
210 if (format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE) {
211 memcpy(dest, source, width*4);
212 continue;
213 }
214
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000215 for (int x = 0; x < width; x++)
216 {
217 unsigned char r;
218 unsigned char g;
219 unsigned char b;
220 unsigned char a;
221
222 switch (format)
223 {
224 case GL_ALPHA:
225 a = source[x];
226 r = 0;
227 g = 0;
228 b = 0;
229 break;
230
231 case GL_LUMINANCE:
232 r = source[x];
233 g = source[x];
234 b = source[x];
235 a = 0xFF;
236 break;
237
238 case GL_LUMINANCE_ALPHA:
239 r = source[2*x+0];
240 g = source[2*x+0];
241 b = source[2*x+0];
242 a = source[2*x+1];
243 break;
244
245 case GL_RGB:
246 switch (type)
247 {
248 case GL_UNSIGNED_BYTE:
249 r = source[x * 3 + 0];
daniel@transgaming.com5ac52152010-04-13 19:53:38 +0000250 g = source[x * 3 + 1];
251 b = source[x * 3 + 2];
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000252 a = 0xFF;
253 break;
254
255 case GL_UNSIGNED_SHORT_5_6_5:
256 {
257 unsigned short rgba = source16[x];
258
259 a = 0xFF;
260 b = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
261 g = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
262 r = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
263 }
264 break;
265
266 default: UNREACHABLE();
267 }
268 break;
269
270 case GL_RGBA:
271 switch (type)
272 {
273 case GL_UNSIGNED_BYTE:
274 r = source[x * 4 + 0];
275 g = source[x * 4 + 1];
276 b = source[x * 4 + 2];
277 a = source[x * 4 + 3];
278 break;
279
280 case GL_UNSIGNED_SHORT_4_4_4_4:
281 {
282 unsigned short rgba = source16[x];
283
284 a = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
285 b = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
286 g = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
287 r = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
288 }
289 break;
290
291 case GL_UNSIGNED_SHORT_5_5_5_1:
292 {
293 unsigned short rgba = source16[x];
294
295 a = (rgba & 0x0001) ? 0xFF : 0;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000296 b = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000297 g = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000298 r = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000299 }
300 break;
301
302 default: UNREACHABLE();
303 }
304 break;
305 default: UNREACHABLE();
306 }
307
308 dest[4 * x + 0] = b;
309 dest[4 * x + 1] = g;
310 dest[4 * x + 2] = r;
311 dest[4 * x + 3] = a;
312 }
313 }
314}
315
daniel@transgaming.com01868132010-08-24 19:21:17 +0000316void Texture::createSurface(GLsizei width, GLsizei height, GLenum format, Image *img)
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000317{
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000318 IDirect3DTexture9 *newTexture = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000319 IDirect3DSurface9 *newSurface = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000320
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000321 if (width != 0 && height != 0)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000322 {
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000323 HRESULT result = getDevice()->CreateTexture(width, height, 1, NULL, selectFormat(format), D3DPOOL_SYSTEMMEM, &newTexture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000324
325 if (FAILED(result))
326 {
327 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
328 return error(GL_OUT_OF_MEMORY);
329 }
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000330
331 newTexture->GetSurfaceLevel(0, &newSurface);
332 newTexture->Release();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000333 }
334
335 if (img->surface) img->surface->Release();
336 img->surface = newSurface;
337
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000338 img->width = width;
339 img->height = height;
340 img->format = format;
daniel@transgaming.com01868132010-08-24 19:21:17 +0000341}
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000342
daniel@transgaming.com01868132010-08-24 19:21:17 +0000343void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
344{
345 createSurface(width, height, format, img);
346
347 if (pixels != NULL && img->surface != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000348 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000349 D3DLOCKED_RECT locked;
daniel@transgaming.com01868132010-08-24 19:21:17 +0000350 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000351
352 ASSERT(SUCCEEDED(result));
353
354 if (SUCCEEDED(result))
355 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000356 loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000357 img->surface->UnlockRect();
358 }
359
360 img->dirty = true;
361 }
362
363 mDirtyMetaData = true;
364}
365
366void Texture::setCompressedImage(GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
367{
368 createSurface(width, height, format, img);
369
370 if (pixels != NULL && img->surface != NULL)
371 {
372 D3DLOCKED_RECT locked;
373 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
374
375 ASSERT(SUCCEEDED(result));
376
377 if (SUCCEEDED(result))
378 {
379 memcpy(locked.pBits, pixels, imageSize);
380 img->surface->UnlockRect();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000381 }
382
383 img->dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000384 }
385
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000386 mDirtyMetaData = true;
387}
388
daniel@transgaming.com31273552010-08-04 13:42:44 +0000389bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000390{
daniel@transgaming.com31273552010-08-04 13:42:44 +0000391 if (width + xoffset > img->width || height + yoffset > img->height)
392 {
393 error(GL_INVALID_VALUE);
394 return false;
395 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000396
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000397 D3DLOCKED_RECT locked;
398 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000399
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000400 ASSERT(SUCCEEDED(result));
401
402 if (SUCCEEDED(result))
403 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000404 loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000405 img->surface->UnlockRect();
406 }
407
408 img->dirty = true;
daniel@transgaming.com31273552010-08-04 13:42:44 +0000409 return true;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000410}
411
daniel@transgaming.com01868132010-08-24 19:21:17 +0000412bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
413{
414 if (width + xoffset > img->width || height + yoffset > img->height)
415 {
416 error(GL_INVALID_VALUE);
417 return false;
418 }
419
420 if (format != getFormat())
421 {
422 error(GL_INVALID_OPERATION);
423 return false;
424 }
425
426 RECT updateRegion;
427 updateRegion.left = xoffset;
428 updateRegion.right = xoffset + width;
429 updateRegion.bottom = yoffset + height;
430 updateRegion.top = yoffset;
431
432 D3DLOCKED_RECT locked;
433 HRESULT result = img->surface->LockRect(&locked, &updateRegion, 0);
434
435 ASSERT(SUCCEEDED(result));
436
437 if (SUCCEEDED(result))
438 {
439 GLsizei inputPitch = ComputeCompressedPitch(width, format);
440 int rows = imageSize / inputPitch;
441 for (int i = 0; i < rows; ++i)
442 {
443 memcpy((void*)((BYTE*)locked.pBits + i * locked.Pitch), (void*)((BYTE*)pixels + i * inputPitch), inputPitch);
444 }
445 img->surface->UnlockRect();
446 }
447
448 img->dirty = true;
449 return true;
450}
451
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000452IDirect3DBaseTexture9 *Texture::getTexture()
453{
454 if (!isComplete())
455 {
456 return NULL;
457 }
458
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000459 if (mDirtyMetaData)
460 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000461 mBaseTexture = createTexture();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000462 mIsRenderable = false;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000463 }
464
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000465 if (mDirtyMetaData || dirtyImageData())
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000466 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000467 updateTexture();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000468 }
469
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000470 mDirtyMetaData = false;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000471 ASSERT(!dirtyImageData());
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000472
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000473 return mBaseTexture;
474}
475
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000476bool Texture::isDirty() const
477{
478 return (mDirty || mDirtyMetaData || dirtyImageData());
479}
480
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000481// Returns the top-level texture surface as a render target
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000482void Texture::needRenderTarget()
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000483{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000484 if (!mIsRenderable)
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000485 {
486 mBaseTexture = convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000487 mIsRenderable = true;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000488 }
489
490 if (dirtyImageData())
491 {
492 updateTexture();
493 }
494
495 mDirtyMetaData = false;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000496}
497
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000498void Texture::dropTexture()
499{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000500 if (mBaseTexture)
501 {
502 mBaseTexture = NULL;
503 }
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000504
505 mIsRenderable = false;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000506}
507
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000508void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000509{
510 mBaseTexture = newTexture;
511 mDirtyMetaData = false;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000512 mIsRenderable = renderable;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000513 mDirty = true;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000514}
515
516
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000517GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
518{
519 if (isPow2(width) && isPow2(height))
520 {
521 return maxlevel;
522 }
523 else
524 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000525 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
526 return 1;
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000527 }
528}
529
530GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
531{
532 return creationLevels(size, size, maxlevel);
533}
534
535int Texture::levelCount() const
536{
537 return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
538}
539
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000540Texture2D::Texture2D(GLuint id) : Texture(id)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000541{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000542 mTexture = NULL;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000543 mColorbufferProxy = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000544}
545
546Texture2D::~Texture2D()
547{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000548 delete mColorbufferProxy;
549
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000550 if (mTexture)
551 {
552 mTexture->Release();
553 mTexture = NULL;
554 }
555}
556
557GLenum Texture2D::getTarget() const
558{
559 return GL_TEXTURE_2D;
560}
561
daniel@transgaming.com01868132010-08-24 19:21:17 +0000562GLenum Texture2D::getFormat() const
563{
564 return mImageArray[0].format;
565}
566
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000567// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
568// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
569// Call this when a particular level of the texture must be defined with a specific format, width and height.
570//
571// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
572// a new height and width for the texture by working backwards from the given width and height.
573bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height)
574{
575 bool widthOkay = (mWidth >> level == width);
576 bool heightOkay = (mHeight >> level == height);
577
578 bool sizeOkay = ((widthOkay && heightOkay)
579 || (widthOkay && mHeight >> level == 0 && height == 1)
580 || (heightOkay && mWidth >> level == 0 && width == 1));
581
582 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0].format);
583
584 if (!textureOkay)
585 {
586 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
587 mImageArray[0].format, mWidth, mHeight,
588 internalFormat, width, height);
589
590 // Purge all the levels and the texture.
591
592 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
593 {
594 if (mImageArray[i].surface != NULL)
595 {
596 mImageArray[i].dirty = false;
597
598 mImageArray[i].surface->Release();
599 mImageArray[i].surface = NULL;
600 }
601 }
602
603 if (mTexture != NULL)
604 {
605 mTexture->Release();
606 mTexture = NULL;
607 dropTexture();
608 }
609
610 mWidth = width << level;
611 mHeight = height << level;
612 mImageArray[0].format = internalFormat;
613 }
614
615 return !textureOkay;
616}
617
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000618void Texture2D::setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000619{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000620 redefineTexture(level, internalFormat, width, height);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000621
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000622 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000623}
624
daniel@transgaming.com01868132010-08-24 19:21:17 +0000625void Texture2D::setCompressedImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
626{
627 redefineTexture(level, internalFormat, width, height);
628
629 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[level]);
630}
631
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000632void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
633{
634 ASSERT(mImageArray[level].surface != NULL);
635
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000636 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000637 {
638 IDirect3DSurface9 *destLevel = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000639 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000640
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000641 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000642
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000643 if (SUCCEEDED(result))
644 {
645 Image *img = &mImageArray[level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000646
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000647 RECT sourceRect;
648 sourceRect.left = xoffset;
649 sourceRect.top = yoffset;
650 sourceRect.right = xoffset + width;
651 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000652
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000653 POINT destPoint;
654 destPoint.x = xoffset;
655 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000656
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000657 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
658 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000659
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000660 destLevel->Release();
661
662 img->dirty = false;
663 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000664 }
665}
666
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000667void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000668{
daniel@transgaming.com31273552010-08-04 13:42:44 +0000669 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
670 {
671 commitRect(level, xoffset, yoffset, width, height);
672 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000673}
674
daniel@transgaming.com01868132010-08-24 19:21:17 +0000675void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
676{
677 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
678 {
679 commitRect(level, xoffset, yoffset, width, height);
680 }
681}
682
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000683void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000684{
685 if (redefineTexture(level, internalFormat, width, height))
686 {
687 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000688 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000689 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +0000690 else
691 {
692 needRenderTarget();
693 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000694
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000695 if (width != 0 && height != 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000696 {
697 RECT sourceRect;
698 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000699 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +0000700 sourceRect.top = y;
701 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000702
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000703 IDirect3DSurface9 *dest;
704 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000705
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000706 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
707 dest->Release();
708 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000709
710 mImageArray[level].width = width;
711 mImageArray[level].height = height;
712 mImageArray[level].format = internalFormat;
713}
714
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000715void Texture2D::copySubImage(GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000716{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000717 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
718 {
719 return error(GL_INVALID_VALUE);
720 }
721
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000722 if (redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height))
723 {
724 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000725 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000726 }
727 else
728 {
daniel@transgaming.comfc23fe22010-05-05 18:48:17 +0000729 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000730 }
731
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000732 if (level < levelCount())
733 {
734 RECT sourceRect;
735 sourceRect.left = x;
736 sourceRect.right = x + width;
737 sourceRect.top = y;
738 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000739
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000740 IDirect3DSurface9 *dest;
741 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000742
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000743 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
744 dest->Release();
745 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000746}
747
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000748// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
749bool Texture2D::isComplete() const
750{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000751 GLsizei width = mImageArray[0].width;
752 GLsizei height = mImageArray[0].height;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000753
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000754 if (width <= 0 || height <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000755 {
756 return false;
757 }
758
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000759 bool mipmapping = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000760
daniel@transgaming.com12d54072010-03-16 06:23:26 +0000761 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000762 {
763 case GL_NEAREST:
764 case GL_LINEAR:
765 mipmapping = false;
766 break;
767 case GL_NEAREST_MIPMAP_NEAREST:
768 case GL_LINEAR_MIPMAP_NEAREST:
769 case GL_NEAREST_MIPMAP_LINEAR:
770 case GL_LINEAR_MIPMAP_LINEAR:
771 mipmapping = true;
772 break;
773 default: UNREACHABLE();
774 }
775
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000776 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
777 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
778 {
779 return false;
780 }
781
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000782 if (mipmapping)
783 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000784 if (!isPow2(width) || !isPow2(height))
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000785 {
786 return false;
787 }
788
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000789 int q = log2(std::max(width, height));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000790
791 for (int level = 1; level <= q; level++)
792 {
793 if (mImageArray[level].format != mImageArray[0].format)
794 {
795 return false;
796 }
797
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000798 if (mImageArray[level].width != std::max(1, width >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000799 {
800 return false;
801 }
802
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000803 if (mImageArray[level].height != std::max(1, height >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000804 {
805 return false;
806 }
807 }
808 }
809
810 return true;
811}
812
daniel@transgaming.com01868132010-08-24 19:21:17 +0000813bool Texture2D::isCompressed() const
814{
815 return IsCompressed(getFormat());
816}
817
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000818// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000819IDirect3DBaseTexture9 *Texture2D::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000820{
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000821 IDirect3DTexture9 *texture;
822
823 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000824 D3DFORMAT format = selectFormat(mImageArray[0].format);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000825
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000826 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000827
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000828 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000829 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000830 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000831 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000832 }
833
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000834 if (mTexture) mTexture->Release();
835 mTexture = texture;
836 return texture;
837}
838
839void Texture2D::updateTexture()
840{
841 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000842
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000843 int levels = levelCount();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000844
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000845 for (int level = 0; level < levels; level++)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000846 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000847 if (mImageArray[level].dirty)
848 {
849 IDirect3DSurface9 *levelSurface = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000850 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000851
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000852 ASSERT(SUCCEEDED(result));
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000853
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000854 if (SUCCEEDED(result))
855 {
856 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
857 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000858
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000859 levelSurface->Release();
860
861 mImageArray[level].dirty = false;
862 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000863 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000864 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000865}
866
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000867IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000868{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000869 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000870
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000871 if (mWidth != 0 && mHeight != 0)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000872 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +0000873 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000874 IDirect3DDevice9 *device = getDevice();
875 D3DFORMAT format = selectFormat(mImageArray[0].format);
876
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000877 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000878
879 if (FAILED(result))
880 {
881 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
882 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
883 }
884
885 if (mTexture != NULL)
886 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000887 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000888 for (int i = 0; i < levels; i++)
889 {
890 IDirect3DSurface9 *source;
891 result = mTexture->GetSurfaceLevel(i, &source);
892
893 if (FAILED(result))
894 {
895 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
896
897 texture->Release();
898
899 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
900 }
901
902 IDirect3DSurface9 *dest;
903 result = texture->GetSurfaceLevel(i, &dest);
904
905 if (FAILED(result))
906 {
907 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
908
909 texture->Release();
910 source->Release();
911
912 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
913 }
914
daniel@transgaming.comae072af2010-05-05 18:47:28 +0000915 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000916 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
917
918 if (FAILED(result))
919 {
920 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
921
922 texture->Release();
923 source->Release();
924 dest->Release();
925
926 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
927 }
928
929 source->Release();
930 dest->Release();
931 }
932 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000933 }
934
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000935 if (mTexture != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000936 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000937 mTexture->Release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000938 }
939
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000940 mTexture = texture;
941 return mTexture;
942}
943
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000944bool Texture2D::dirtyImageData() const
945{
946 int q = log2(std::max(mWidth, mHeight));
947
948 for (int i = 0; i <= q; i++)
949 {
950 if (mImageArray[i].dirty) return true;
951 }
952
953 return false;
954}
955
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +0000956void Texture2D::generateMipmaps()
957{
958 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
959 {
960 return error(GL_INVALID_OPERATION);
961 }
962
963 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
964 unsigned int q = log2(std::max(mWidth, mHeight));
965 for (unsigned int i = 1; i <= q; i++)
966 {
967 if (mImageArray[i].surface != NULL)
968 {
969 mImageArray[i].surface->Release();
970 mImageArray[i].surface = NULL;
971 }
972
973 mImageArray[i].dirty = false;
974
975 mImageArray[i].format = mImageArray[0].format;
976 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
977 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
978 }
979
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000980 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +0000981
982 for (unsigned int i = 1; i <= q; i++)
983 {
984 IDirect3DSurface9 *upper = NULL;
985 IDirect3DSurface9 *lower = NULL;
986
987 mTexture->GetSurfaceLevel(i-1, &upper);
988 mTexture->GetSurfaceLevel(i, &lower);
989
990 if (upper != NULL && lower != NULL)
991 {
992 getBlitter()->boxFilter(upper, lower);
993 }
994
995 if (upper != NULL) upper->Release();
996 if (lower != NULL) lower->Release();
997 }
998}
999
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001000Renderbuffer *Texture2D::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001001{
1002 if (target != GL_TEXTURE_2D)
1003 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001004 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001005 }
1006
1007 if (mColorbufferProxy == NULL)
1008 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001009 mColorbufferProxy = new Renderbuffer(id(), new TextureColorbufferProxy(this, target));
1010 mColorbufferProxy->addRef();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001011 }
1012
1013 return mColorbufferProxy;
1014}
1015
1016IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1017{
1018 ASSERT(target == GL_TEXTURE_2D);
1019
1020 needRenderTarget();
1021
1022 IDirect3DSurface9 *renderTarget = NULL;
1023 mTexture->GetSurfaceLevel(0, &renderTarget);
1024
1025 return renderTarget;
1026}
1027
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001028TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001029{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001030 mTexture = NULL;
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001031
1032 for (int i = 0; i < 6; i++)
1033 {
1034 mFaceProxies[i] = NULL;
1035 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001036}
1037
1038TextureCubeMap::~TextureCubeMap()
1039{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001040 for (int i = 0; i < 6; i++)
1041 {
1042 delete mFaceProxies[i];
1043 }
1044
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001045 if (mTexture)
1046 {
1047 mTexture->Release();
1048 mTexture = NULL;
1049 }
1050}
1051
1052GLenum TextureCubeMap::getTarget() const
1053{
1054 return GL_TEXTURE_CUBE_MAP;
1055}
1056
daniel@transgaming.com01868132010-08-24 19:21:17 +00001057GLenum TextureCubeMap::getFormat() const
1058{
1059 return mImageArray[0][0].format;
1060}
1061
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001062void TextureCubeMap::setImagePosX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001063{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001064 setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001065}
1066
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001067void TextureCubeMap::setImageNegX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001068{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001069 setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001070}
1071
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001072void TextureCubeMap::setImagePosY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001073{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001074 setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001075}
1076
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001077void TextureCubeMap::setImageNegY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001078{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001079 setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001080}
1081
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001082void TextureCubeMap::setImagePosZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001083{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001084 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001085}
1086
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001087void TextureCubeMap::setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001088{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001089 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001090}
1091
daniel@transgaming.com01868132010-08-24 19:21:17 +00001092void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1093{
1094 redefineTexture(level, internalFormat, width);
1095
1096 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[faceIndex(face)][level]);
1097}
1098
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001099void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1100{
1101 int face = faceIndex(faceTarget);
1102
1103 ASSERT(mImageArray[face][level].surface != NULL);
1104
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001105 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001106 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001107 IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level);
1108 ASSERT(destLevel != NULL);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001109
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001110 if (destLevel != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001111 {
1112 Image *img = &mImageArray[face][level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001113
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001114 RECT sourceRect;
1115 sourceRect.left = xoffset;
1116 sourceRect.top = yoffset;
1117 sourceRect.right = xoffset + width;
1118 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001119
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001120 POINT destPoint;
1121 destPoint.x = xoffset;
1122 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001123
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001124 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001125 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001126
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001127 destLevel->Release();
1128
1129 img->dirty = false;
1130 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001131 }
1132}
1133
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001134void TextureCubeMap::subImage(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001135{
daniel@transgaming.com31273552010-08-04 13:42:44 +00001136 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(face)][level]))
1137 {
1138 commitRect(face, level, xoffset, yoffset, width, height);
1139 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001140}
1141
daniel@transgaming.com01868132010-08-24 19:21:17 +00001142void TextureCubeMap::subImageCompressed(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1143{
1144 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(face)][level]))
1145 {
1146 commitRect(face, level, xoffset, yoffset, width, height);
1147 }
1148}
1149
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001150// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001151bool TextureCubeMap::isComplete() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001152{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001153 int size = mImageArray[0][0].width;
1154
1155 if (size <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001156 {
1157 return false;
1158 }
1159
1160 bool mipmapping;
1161
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001162 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001163 {
1164 case GL_NEAREST:
1165 case GL_LINEAR:
1166 mipmapping = false;
1167 break;
1168 case GL_NEAREST_MIPMAP_NEAREST:
1169 case GL_LINEAR_MIPMAP_NEAREST:
1170 case GL_NEAREST_MIPMAP_LINEAR:
1171 case GL_LINEAR_MIPMAP_LINEAR:
1172 mipmapping = true;
1173 break;
1174 default: UNREACHABLE();
1175 }
1176
1177 for (int face = 0; face < 6; face++)
1178 {
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001179 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001180 {
1181 return false;
1182 }
1183 }
1184
1185 if (mipmapping)
1186 {
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001187 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1188 {
1189 return false;
1190 }
1191
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001192 int q = log2(size);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001193
1194 for (int face = 0; face < 6; face++)
1195 {
1196 for (int level = 1; level <= q; level++)
1197 {
1198 if (mImageArray[face][level].format != mImageArray[0][0].format)
1199 {
1200 return false;
1201 }
1202
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001203 if (mImageArray[face][level].width != std::max(1, size >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001204 {
1205 return false;
1206 }
1207
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001208 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001209 }
1210 }
1211 }
1212
1213 return true;
1214}
1215
daniel@transgaming.com01868132010-08-24 19:21:17 +00001216bool TextureCubeMap::isCompressed() const
1217{
1218 return IsCompressed(getFormat());
1219}
1220
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001221// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001222IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001223{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001224 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001225 D3DFORMAT format = selectFormat(mImageArray[0][0].format);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001226
1227 IDirect3DCubeTexture9 *texture;
1228
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001229 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001230
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001231 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001232 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001233 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001234 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001235 }
1236
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001237 if (mTexture) mTexture->Release();
1238
1239 mTexture = texture;
1240 return mTexture;
1241}
1242
1243void TextureCubeMap::updateTexture()
1244{
1245 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001246
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001247 for (int face = 0; face < 6; face++)
1248 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001249 int levels = levelCount();
1250 for (int level = 0; level < levels; level++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001251 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001252 Image *img = &mImageArray[face][level];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001253
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001254 if (img->dirty)
1255 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001256 IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level);
1257 ASSERT(levelSurface != NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001258
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001259 if (levelSurface != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001260 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001261 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001262 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001263
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001264 levelSurface->Release();
1265
1266 img->dirty = false;
1267 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001268 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001269 }
1270 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001271}
1272
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001273IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
1274{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001275 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001276
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001277 if (mWidth != 0)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001278 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001279 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001280 IDirect3DDevice9 *device = getDevice();
1281 D3DFORMAT format = selectFormat(mImageArray[0][0].format);
1282
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001283 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001284
1285 if (FAILED(result))
1286 {
1287 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1288 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1289 }
1290
1291 if (mTexture != NULL)
1292 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001293 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001294 for (int f = 0; f < 6; f++)
1295 {
1296 for (int i = 0; i < levels; i++)
1297 {
1298 IDirect3DSurface9 *source;
1299 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
1300
1301 if (FAILED(result))
1302 {
1303 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1304
1305 texture->Release();
1306
1307 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1308 }
1309
1310 IDirect3DSurface9 *dest;
1311 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
1312
1313 if (FAILED(result))
1314 {
1315 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1316
1317 texture->Release();
1318 source->Release();
1319
1320 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1321 }
1322
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001323 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001324 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1325
1326 if (FAILED(result))
1327 {
1328 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1329
1330 texture->Release();
1331 source->Release();
1332 dest->Release();
1333
1334 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1335 }
1336 }
1337 }
1338 }
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001339 }
1340
1341 if (mTexture != NULL)
1342 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001343 mTexture->Release();
1344 }
1345
1346 mTexture = texture;
1347 return mTexture;
1348}
1349
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001350void TextureCubeMap::setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001351{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001352 redefineTexture(level, internalFormat, width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001353
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001354 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001355}
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001356
1357unsigned int TextureCubeMap::faceIndex(GLenum face)
1358{
1359 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1360 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1361 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1362 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1363 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1364
1365 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1366}
1367
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001368bool TextureCubeMap::dirtyImageData() const
1369{
1370 int q = log2(mWidth);
1371
1372 for (int f = 0; f < 6; f++)
1373 {
1374 for (int i = 0; i <= q; i++)
1375 {
1376 if (mImageArray[f][i].dirty) return true;
1377 }
1378 }
1379
1380 return false;
1381}
1382
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001383// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1384// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
1385// Call this when a particular level of the texture must be defined with a specific format, width and height.
1386//
1387// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
1388// a new size for the texture by working backwards from the given size.
1389bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
1390{
1391 // Are these settings compatible with level 0?
1392 bool sizeOkay = (mImageArray[0][0].width >> level == width);
1393
1394 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
1395
1396 if (!textureOkay)
1397 {
1398 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
1399 mImageArray[0][0].format, mImageArray[0][0].width,
1400 internalFormat, width);
1401
1402 // Purge all the levels and the texture.
1403 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
1404 {
1405 for (int f = 0; f < 6; f++)
1406 {
1407 if (mImageArray[f][i].surface != NULL)
1408 {
1409 mImageArray[f][i].dirty = false;
1410
1411 mImageArray[f][i].surface->Release();
1412 mImageArray[f][i].surface = NULL;
1413 }
1414 }
1415 }
1416
1417 if (mTexture != NULL)
1418 {
1419 mTexture->Release();
1420 mTexture = NULL;
1421 dropTexture();
1422 }
1423
1424 mWidth = width << level;
1425 mImageArray[0][0].width = width << level;
1426 mHeight = width << level;
1427 mImageArray[0][0].height = width << level;
1428
1429 mImageArray[0][0].format = internalFormat;
1430 }
1431
1432 return !textureOkay;
1433}
1434
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001435void TextureCubeMap::copyImage(GLenum face, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001436{
1437 unsigned int faceindex = faceIndex(face);
1438
1439 if (redefineTexture(level, internalFormat, width))
1440 {
1441 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001442 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001443 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001444 else
1445 {
1446 needRenderTarget();
1447 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001448
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001449 ASSERT(width == height);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001450
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001451 if (width > 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001452 {
1453 RECT sourceRect;
1454 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001455 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +00001456 sourceRect.top = y;
1457 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001458
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001459 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
1460
1461 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1462 dest->Release();
1463 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001464
1465 mImageArray[faceindex][level].width = width;
1466 mImageArray[faceindex][level].height = height;
1467 mImageArray[faceindex][level].format = internalFormat;
1468}
1469
1470IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(unsigned int faceIdentifier, unsigned int level)
1471{
1472 unsigned int faceIndex;
1473
1474 if (faceIdentifier < 6)
1475 {
1476 faceIndex = faceIdentifier;
1477 }
1478 else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
1479 {
1480 faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1481 }
1482 else
1483 {
1484 UNREACHABLE();
1485 faceIndex = 0;
1486 }
1487
1488 if (mTexture == NULL)
1489 {
1490 UNREACHABLE();
1491 return NULL;
1492 }
1493
1494 IDirect3DSurface9 *surface = NULL;
1495
1496 HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface);
1497
1498 return (SUCCEEDED(hr)) ? surface : NULL;
1499}
1500
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001501void TextureCubeMap::copySubImage(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001502{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001503 GLsizei size = mImageArray[faceIndex(face)][level].width;
1504
1505 if (xoffset + width > size || yoffset + height > size)
1506 {
1507 return error(GL_INVALID_VALUE);
1508 }
1509
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001510 if (redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width))
1511 {
1512 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001513 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001514 }
1515 else
1516 {
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001517 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001518 }
1519
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001520 if (level < levelCount())
1521 {
1522 RECT sourceRect;
1523 sourceRect.left = x;
1524 sourceRect.right = x + width;
1525 sourceRect.top = y;
1526 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001527
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001528 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001529
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001530 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
1531 dest->Release();
1532 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001533}
1534
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001535bool TextureCubeMap::isCubeComplete() const
1536{
1537 if (mImageArray[0][0].width == 0)
1538 {
1539 return false;
1540 }
1541
1542 for (unsigned int f = 1; f < 6; f++)
1543 {
1544 if (mImageArray[f][0].width != mImageArray[0][0].width
1545 || mImageArray[f][0].format != mImageArray[0][0].format)
1546 {
1547 return false;
1548 }
1549 }
1550
1551 return true;
1552}
1553
1554void TextureCubeMap::generateMipmaps()
1555{
1556 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
1557 {
1558 return error(GL_INVALID_OPERATION);
1559 }
1560
1561 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1562 unsigned int q = log2(mImageArray[0][0].width);
1563 for (unsigned int f = 0; f < 6; f++)
1564 {
1565 for (unsigned int i = 1; i <= q; i++)
1566 {
1567 if (mImageArray[f][i].surface != NULL)
1568 {
1569 mImageArray[f][i].surface->Release();
1570 mImageArray[f][i].surface = NULL;
1571 }
1572
1573 mImageArray[f][i].dirty = false;
1574
1575 mImageArray[f][i].format = mImageArray[f][0].format;
1576 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
1577 mImageArray[f][i].height = mImageArray[f][i].width;
1578 }
1579 }
1580
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001581 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001582
1583 for (unsigned int f = 0; f < 6; f++)
1584 {
1585 for (unsigned int i = 1; i <= q; i++)
1586 {
1587 IDirect3DSurface9 *upper = getCubeMapSurface(f, i-1);
1588 IDirect3DSurface9 *lower = getCubeMapSurface(f, i);
1589
1590 if (upper != NULL && lower != NULL)
1591 {
1592 getBlitter()->boxFilter(upper, lower);
1593 }
1594
1595 if (upper != NULL) upper->Release();
1596 if (lower != NULL) lower->Release();
1597 }
1598 }
1599}
1600
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001601Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001602{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001603 if (!IsCubemapTextureTarget(target))
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001604 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001605 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001606 }
1607
1608 unsigned int face = faceIndex(target);
1609
1610 if (mFaceProxies[face] == NULL)
1611 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001612 mFaceProxies[face] = new Renderbuffer(id(), new TextureColorbufferProxy(this, target));
1613 mFaceProxies[face]->addRef();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001614 }
1615
1616 return mFaceProxies[face];
1617}
1618
1619IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
1620{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001621 ASSERT(IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001622
1623 needRenderTarget();
1624
1625 IDirect3DSurface9 *renderTarget = NULL;
1626 mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex(target)), 0, &renderTarget);
1627
1628 return renderTarget;
1629}
1630
1631Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
1632 : Colorbuffer(NULL), mTexture(texture), mTarget(target)
1633{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001634 ASSERT(target == GL_TEXTURE_2D || IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001635}
1636
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001637void Texture::TextureColorbufferProxy::addRef() const
1638{
1639 mTexture->addRef();
1640}
1641
1642void Texture::TextureColorbufferProxy::release() const
1643{
1644 mTexture->release();
1645}
1646
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001647IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
1648{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001649 if (mRenderTarget) mRenderTarget->Release();
1650
1651 mRenderTarget = mTexture->getRenderTarget(mTarget);
1652
1653 return mRenderTarget;
1654}
1655
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001656int Texture::TextureColorbufferProxy::getWidth() const
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001657{
daniel@transgaming.com866f3182010-05-20 19:28:22 +00001658 return mTexture->getWidth();
1659}
1660
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001661int Texture::TextureColorbufferProxy::getHeight() const
daniel@transgaming.com866f3182010-05-20 19:28:22 +00001662{
1663 return mTexture->getHeight();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001664}
1665
daniel@transgaming.com01868132010-08-24 19:21:17 +00001666GLenum Texture::TextureColorbufferProxy::getFormat() const
1667{
1668 return mTexture->getFormat();
1669}
1670
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001671}