blob: 2e0b1e35cc7cbf85b35ce45d509c462eb7665f88 [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
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000203 switch (format)
204 {
205 case GL_ALPHA:
206 loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
207 break;
208
209 case GL_LUMINANCE:
210 loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
211 break;
212
213 case GL_LUMINANCE_ALPHA:
214 loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
215 break;
216
217 case GL_RGB:
218 switch (type)
219 {
220 case GL_UNSIGNED_BYTE:
221 loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
222 break;
223
224 case GL_UNSIGNED_SHORT_5_6_5:
225 loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
226 break;
227
228 default: UNREACHABLE();
229 }
230 break;
231
232 case GL_RGBA:
233 switch (type)
234 {
235 case GL_UNSIGNED_BYTE:
236 loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
237 break;
238
239 case GL_UNSIGNED_SHORT_4_4_4_4:
240 loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
241 break;
242
243 case GL_UNSIGNED_SHORT_5_5_5_1:
244 loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
245 break;
246
247 default: UNREACHABLE();
248 }
249 break;
250 case GL_BGRA_EXT:
251 switch (type)
252 {
253 case GL_UNSIGNED_BYTE:
254 loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
255 break;
256
257 default: UNREACHABLE();
258 }
259 break;
260 default: UNREACHABLE();
261 }
262}
263
264void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
265 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
266{
267 const unsigned char *source = NULL;
268 unsigned char *dest = NULL;
269
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000270 for (int y = 0; y < height; y++)
271 {
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000272 source = static_cast<const unsigned char*>(input) + y * inputPitch;
273 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000274 for (int x = 0; x < width; x++)
275 {
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000276 dest[4 * x + 0] = 0;
277 dest[4 * x + 1] = 0;
278 dest[4 * x + 2] = 0;
279 dest[4 * x + 3] = source[x];
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000280 }
281 }
282}
283
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000284void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
285 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
286{
287 const unsigned char *source = NULL;
288 unsigned char *dest = NULL;
289
290 for (int y = 0; y < height; y++)
291 {
292 source = static_cast<const unsigned char*>(input) + y * inputPitch;
293 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
294 for (int x = 0; x < width; x++)
295 {
296 dest[4 * x + 0] = source[x];
297 dest[4 * x + 1] = source[x];
298 dest[4 * x + 2] = source[x];
299 dest[4 * x + 3] = 0xFF;
300 }
301 }
302}
303
304void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
305 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
306{
307 const unsigned char *source = NULL;
308 unsigned char *dest = NULL;
309
310 for (int y = 0; y < height; y++)
311 {
312 source = static_cast<const unsigned char*>(input) + y * inputPitch;
313 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
314 for (int x = 0; x < width; x++)
315 {
316 dest[4 * x + 0] = source[2*x+0];
317 dest[4 * x + 1] = source[2*x+0];
318 dest[4 * x + 2] = source[2*x+0];
319 dest[4 * x + 3] = source[2*x+1];
320 }
321 }
322}
323
324void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
325 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
326{
327 const unsigned char *source = NULL;
328 unsigned char *dest = NULL;
329
330 for (int y = 0; y < height; y++)
331 {
332 source = static_cast<const unsigned char*>(input) + y * inputPitch;
333 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
334 for (int x = 0; x < width; x++)
335 {
336 dest[4 * x + 0] = source[x * 3 + 2];
337 dest[4 * x + 1] = source[x * 3 + 1];
338 dest[4 * x + 2] = source[x * 3 + 0];
339 dest[4 * x + 3] = 0xFF;
340 }
341 }
342}
343
344void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
345 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
346{
347 const unsigned short *source = NULL;
348 unsigned char *dest = NULL;
349
350 for (int y = 0; y < height; y++)
351 {
352 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
353 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
354 for (int x = 0; x < width; x++)
355 {
356 unsigned short rgba = source[x];
357 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
358 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
359 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
360 dest[4 * x + 3] = 0xFF;
361 }
362 }
363}
364
365void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
366 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
367{
368 const unsigned char *source = NULL;
369 unsigned char *dest = NULL;
370
371 for (int y = 0; y < height; y++)
372 {
373 source = static_cast<const unsigned char*>(input) + y * inputPitch;
374 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
375 for (int x = 0; x < width; x++)
376 {
377 dest[4 * x + 0] = source[x * 4 + 2];
378 dest[4 * x + 1] = source[x * 4 + 1];
379 dest[4 * x + 2] = source[x * 4 + 0];
380 dest[4 * x + 3] = source[x * 4 + 3];
381 }
382 }
383}
384
385void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
386 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
387{
388 const unsigned short *source = NULL;
389 unsigned char *dest = NULL;
390
391 for (int y = 0; y < height; y++)
392 {
393 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
394 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
395 for (int x = 0; x < width; x++)
396 {
397 unsigned short rgba = source[x];
398 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
399 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
400 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
401 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
402 }
403 }
404}
405
406void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
407 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
408{
409 const unsigned short *source = NULL;
410 unsigned char *dest = NULL;
411
412 for (int y = 0; y < height; y++)
413 {
414 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
415 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
416 for (int x = 0; x < width; x++)
417 {
418 unsigned short rgba = source[x];
419 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
420 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
421 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
422 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
423 }
424 }
425}
426
427void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
428 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
429{
430 const unsigned char *source = NULL;
431 unsigned char *dest = NULL;
432
433 for (int y = 0; y < height; y++)
434 {
435 source = static_cast<const unsigned char*>(input) + y * inputPitch;
436 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
437 memcpy(dest, source, width*4);
438 }
439}
440
daniel@transgaming.com01868132010-08-24 19:21:17 +0000441void Texture::createSurface(GLsizei width, GLsizei height, GLenum format, Image *img)
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000442{
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000443 IDirect3DTexture9 *newTexture = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000444 IDirect3DSurface9 *newSurface = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000445
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000446 if (width != 0 && height != 0)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000447 {
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000448 int levelToFetch = 0;
449 GLsizei requestWidth = width;
450 GLsizei requestHeight = height;
451 if (IsCompressed(format) && (width % 4 != 0 || height % 4 != 0))
452 {
453 bool isMult4 = false;
454 int upsampleCount = 0;
455 while (!isMult4)
456 {
457 requestWidth <<= 1;
458 requestHeight <<= 1;
459 upsampleCount++;
460 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
461 {
462 isMult4 = true;
463 }
464 }
465 levelToFetch = upsampleCount;
466 }
467
468 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, selectFormat(format),
469 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000470
471 if (FAILED(result))
472 {
473 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
474 return error(GL_OUT_OF_MEMORY);
475 }
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000476
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000477 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000478 newTexture->Release();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000479 }
480
481 if (img->surface) img->surface->Release();
482 img->surface = newSurface;
483
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000484 img->width = width;
485 img->height = height;
486 img->format = format;
daniel@transgaming.com01868132010-08-24 19:21:17 +0000487}
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000488
daniel@transgaming.com01868132010-08-24 19:21:17 +0000489void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
490{
491 createSurface(width, height, format, img);
492
493 if (pixels != NULL && img->surface != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000494 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000495 D3DLOCKED_RECT locked;
daniel@transgaming.com01868132010-08-24 19:21:17 +0000496 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000497
498 ASSERT(SUCCEEDED(result));
499
500 if (SUCCEEDED(result))
501 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000502 loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000503 img->surface->UnlockRect();
504 }
505
506 img->dirty = true;
507 }
508
509 mDirtyMetaData = true;
510}
511
512void Texture::setCompressedImage(GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
513{
514 createSurface(width, height, format, img);
515
516 if (pixels != NULL && img->surface != NULL)
517 {
518 D3DLOCKED_RECT locked;
519 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
520
521 ASSERT(SUCCEEDED(result));
522
523 if (SUCCEEDED(result))
524 {
525 memcpy(locked.pBits, pixels, imageSize);
526 img->surface->UnlockRect();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000527 }
528
529 img->dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000530 }
531
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000532 mDirtyMetaData = true;
533}
534
daniel@transgaming.com31273552010-08-04 13:42:44 +0000535bool 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 +0000536{
daniel@transgaming.com31273552010-08-04 13:42:44 +0000537 if (width + xoffset > img->width || height + yoffset > img->height)
538 {
539 error(GL_INVALID_VALUE);
540 return false;
541 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000542
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000543 D3DLOCKED_RECT locked;
544 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000545
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000546 ASSERT(SUCCEEDED(result));
547
548 if (SUCCEEDED(result))
549 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000550 loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000551 img->surface->UnlockRect();
552 }
553
554 img->dirty = true;
daniel@transgaming.com31273552010-08-04 13:42:44 +0000555 return true;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000556}
557
daniel@transgaming.com01868132010-08-24 19:21:17 +0000558bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
559{
560 if (width + xoffset > img->width || height + yoffset > img->height)
561 {
562 error(GL_INVALID_VALUE);
563 return false;
564 }
565
566 if (format != getFormat())
567 {
568 error(GL_INVALID_OPERATION);
569 return false;
570 }
571
572 RECT updateRegion;
573 updateRegion.left = xoffset;
574 updateRegion.right = xoffset + width;
575 updateRegion.bottom = yoffset + height;
576 updateRegion.top = yoffset;
577
578 D3DLOCKED_RECT locked;
579 HRESULT result = img->surface->LockRect(&locked, &updateRegion, 0);
580
581 ASSERT(SUCCEEDED(result));
582
583 if (SUCCEEDED(result))
584 {
585 GLsizei inputPitch = ComputeCompressedPitch(width, format);
586 int rows = imageSize / inputPitch;
587 for (int i = 0; i < rows; ++i)
588 {
589 memcpy((void*)((BYTE*)locked.pBits + i * locked.Pitch), (void*)((BYTE*)pixels + i * inputPitch), inputPitch);
590 }
591 img->surface->UnlockRect();
592 }
593
594 img->dirty = true;
595 return true;
596}
597
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000598IDirect3DBaseTexture9 *Texture::getTexture()
599{
600 if (!isComplete())
601 {
602 return NULL;
603 }
604
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000605 if (mDirtyMetaData)
606 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000607 mBaseTexture = createTexture();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000608 mIsRenderable = false;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000609 }
610
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000611 if (mDirtyMetaData || dirtyImageData())
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000612 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000613 updateTexture();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000614 }
615
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000616 mDirtyMetaData = false;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000617 ASSERT(!dirtyImageData());
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000618
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000619 return mBaseTexture;
620}
621
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000622bool Texture::isDirty() const
623{
624 return (mDirty || mDirtyMetaData || dirtyImageData());
625}
626
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000627// Returns the top-level texture surface as a render target
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000628void Texture::needRenderTarget()
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000629{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000630 if (!mIsRenderable)
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000631 {
632 mBaseTexture = convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000633 mIsRenderable = true;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000634 }
635
636 if (dirtyImageData())
637 {
638 updateTexture();
639 }
640
641 mDirtyMetaData = false;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000642}
643
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000644void Texture::dropTexture()
645{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000646 if (mBaseTexture)
647 {
648 mBaseTexture = NULL;
649 }
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000650
651 mIsRenderable = false;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000652}
653
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000654void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000655{
656 mBaseTexture = newTexture;
657 mDirtyMetaData = false;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000658 mIsRenderable = renderable;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000659 mDirty = true;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000660}
661
662
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000663GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
664{
665 if (isPow2(width) && isPow2(height))
666 {
667 return maxlevel;
668 }
669 else
670 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000671 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
672 return 1;
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000673 }
674}
675
676GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
677{
678 return creationLevels(size, size, maxlevel);
679}
680
681int Texture::levelCount() const
682{
683 return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
684}
685
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000686Texture2D::Texture2D(GLuint id) : Texture(id)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000687{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000688 mTexture = NULL;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000689 mColorbufferProxy = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000690}
691
692Texture2D::~Texture2D()
693{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000694 delete mColorbufferProxy;
695
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000696 if (mTexture)
697 {
698 mTexture->Release();
699 mTexture = NULL;
700 }
701}
702
703GLenum Texture2D::getTarget() const
704{
705 return GL_TEXTURE_2D;
706}
707
daniel@transgaming.com01868132010-08-24 19:21:17 +0000708GLenum Texture2D::getFormat() const
709{
710 return mImageArray[0].format;
711}
712
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000713// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
714// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
715// Call this when a particular level of the texture must be defined with a specific format, width and height.
716//
717// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
718// a new height and width for the texture by working backwards from the given width and height.
719bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height)
720{
721 bool widthOkay = (mWidth >> level == width);
722 bool heightOkay = (mHeight >> level == height);
723
724 bool sizeOkay = ((widthOkay && heightOkay)
725 || (widthOkay && mHeight >> level == 0 && height == 1)
726 || (heightOkay && mWidth >> level == 0 && width == 1));
727
728 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0].format);
729
730 if (!textureOkay)
731 {
732 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
733 mImageArray[0].format, mWidth, mHeight,
734 internalFormat, width, height);
735
736 // Purge all the levels and the texture.
737
738 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
739 {
740 if (mImageArray[i].surface != NULL)
741 {
742 mImageArray[i].dirty = false;
743
744 mImageArray[i].surface->Release();
745 mImageArray[i].surface = NULL;
746 }
747 }
748
749 if (mTexture != NULL)
750 {
751 mTexture->Release();
752 mTexture = NULL;
753 dropTexture();
754 }
755
756 mWidth = width << level;
757 mHeight = height << level;
758 mImageArray[0].format = internalFormat;
759 }
760
761 return !textureOkay;
762}
763
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000764void 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 +0000765{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000766 redefineTexture(level, internalFormat, width, height);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000767
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000768 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000769}
770
daniel@transgaming.com01868132010-08-24 19:21:17 +0000771void Texture2D::setCompressedImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
772{
773 redefineTexture(level, internalFormat, width, height);
774
775 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[level]);
776}
777
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000778void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
779{
780 ASSERT(mImageArray[level].surface != NULL);
781
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000782 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000783 {
784 IDirect3DSurface9 *destLevel = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000785 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000786
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000787 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000788
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000789 if (SUCCEEDED(result))
790 {
791 Image *img = &mImageArray[level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000792
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000793 RECT sourceRect;
794 sourceRect.left = xoffset;
795 sourceRect.top = yoffset;
796 sourceRect.right = xoffset + width;
797 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000798
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000799 POINT destPoint;
800 destPoint.x = xoffset;
801 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000802
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000803 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
804 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000805
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000806 destLevel->Release();
807
808 img->dirty = false;
809 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000810 }
811}
812
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000813void 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 +0000814{
daniel@transgaming.com31273552010-08-04 13:42:44 +0000815 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
816 {
817 commitRect(level, xoffset, yoffset, width, height);
818 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000819}
820
daniel@transgaming.com01868132010-08-24 19:21:17 +0000821void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
822{
823 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
824 {
825 commitRect(level, xoffset, yoffset, width, height);
826 }
827}
828
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000829void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000830{
831 if (redefineTexture(level, internalFormat, width, height))
832 {
833 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000834 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000835 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +0000836 else
837 {
838 needRenderTarget();
839 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000840
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000841 if (width != 0 && height != 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000842 {
843 RECT sourceRect;
844 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000845 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +0000846 sourceRect.top = y;
847 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000848
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000849 IDirect3DSurface9 *dest;
850 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000851
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000852 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
853 dest->Release();
854 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000855
856 mImageArray[level].width = width;
857 mImageArray[level].height = height;
858 mImageArray[level].format = internalFormat;
859}
860
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000861void 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 +0000862{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000863 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
864 {
865 return error(GL_INVALID_VALUE);
866 }
867
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000868 if (redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height))
869 {
870 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000871 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000872 }
873 else
874 {
daniel@transgaming.comfc23fe22010-05-05 18:48:17 +0000875 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000876 }
877
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000878 if (level < levelCount())
879 {
880 RECT sourceRect;
881 sourceRect.left = x;
882 sourceRect.right = x + width;
883 sourceRect.top = y;
884 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000885
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000886 IDirect3DSurface9 *dest;
887 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000888
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000889 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
890 dest->Release();
891 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000892}
893
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000894// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
895bool Texture2D::isComplete() const
896{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000897 GLsizei width = mImageArray[0].width;
898 GLsizei height = mImageArray[0].height;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000899
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000900 if (width <= 0 || height <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000901 {
902 return false;
903 }
904
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000905 bool mipmapping = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000906
daniel@transgaming.com12d54072010-03-16 06:23:26 +0000907 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000908 {
909 case GL_NEAREST:
910 case GL_LINEAR:
911 mipmapping = false;
912 break;
913 case GL_NEAREST_MIPMAP_NEAREST:
914 case GL_LINEAR_MIPMAP_NEAREST:
915 case GL_NEAREST_MIPMAP_LINEAR:
916 case GL_LINEAR_MIPMAP_LINEAR:
917 mipmapping = true;
918 break;
919 default: UNREACHABLE();
920 }
921
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000922 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
923 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
924 {
925 return false;
926 }
927
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000928 if (mipmapping)
929 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000930 if (!isPow2(width) || !isPow2(height))
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000931 {
932 return false;
933 }
934
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000935 int q = log2(std::max(width, height));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000936
937 for (int level = 1; level <= q; level++)
938 {
939 if (mImageArray[level].format != mImageArray[0].format)
940 {
941 return false;
942 }
943
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000944 if (mImageArray[level].width != std::max(1, width >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000945 {
946 return false;
947 }
948
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000949 if (mImageArray[level].height != std::max(1, height >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000950 {
951 return false;
952 }
953 }
954 }
955
956 return true;
957}
958
daniel@transgaming.com01868132010-08-24 19:21:17 +0000959bool Texture2D::isCompressed() const
960{
961 return IsCompressed(getFormat());
962}
963
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000964// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000965IDirect3DBaseTexture9 *Texture2D::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000966{
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000967 IDirect3DTexture9 *texture;
968
969 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000970 D3DFORMAT format = selectFormat(mImageArray[0].format);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000971
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000972 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000973
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000974 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000975 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000976 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000977 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000978 }
979
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000980 if (mTexture) mTexture->Release();
981 mTexture = texture;
982 return texture;
983}
984
985void Texture2D::updateTexture()
986{
987 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000988
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000989 int levels = levelCount();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000990
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000991 for (int level = 0; level < levels; level++)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000992 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000993 if (mImageArray[level].dirty)
994 {
995 IDirect3DSurface9 *levelSurface = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000996 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000997
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000998 ASSERT(SUCCEEDED(result));
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000999
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001000 if (SUCCEEDED(result))
1001 {
1002 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1003 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001004
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001005 levelSurface->Release();
1006
1007 mImageArray[level].dirty = false;
1008 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001009 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001010 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001011}
1012
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001013IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001014{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001015 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001016
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001017 if (mWidth != 0 && mHeight != 0)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001018 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001019 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001020 IDirect3DDevice9 *device = getDevice();
1021 D3DFORMAT format = selectFormat(mImageArray[0].format);
1022
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001023 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 +00001024
1025 if (FAILED(result))
1026 {
1027 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1028 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1029 }
1030
1031 if (mTexture != NULL)
1032 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001033 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001034 for (int i = 0; i < levels; i++)
1035 {
1036 IDirect3DSurface9 *source;
1037 result = mTexture->GetSurfaceLevel(i, &source);
1038
1039 if (FAILED(result))
1040 {
1041 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1042
1043 texture->Release();
1044
1045 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1046 }
1047
1048 IDirect3DSurface9 *dest;
1049 result = texture->GetSurfaceLevel(i, &dest);
1050
1051 if (FAILED(result))
1052 {
1053 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1054
1055 texture->Release();
1056 source->Release();
1057
1058 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1059 }
1060
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001061 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001062 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1063
1064 if (FAILED(result))
1065 {
1066 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1067
1068 texture->Release();
1069 source->Release();
1070 dest->Release();
1071
1072 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1073 }
1074
1075 source->Release();
1076 dest->Release();
1077 }
1078 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001079 }
1080
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001081 if (mTexture != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001082 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001083 mTexture->Release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001084 }
1085
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001086 mTexture = texture;
1087 return mTexture;
1088}
1089
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001090bool Texture2D::dirtyImageData() const
1091{
1092 int q = log2(std::max(mWidth, mHeight));
1093
1094 for (int i = 0; i <= q; i++)
1095 {
1096 if (mImageArray[i].dirty) return true;
1097 }
1098
1099 return false;
1100}
1101
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001102void Texture2D::generateMipmaps()
1103{
1104 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1105 {
1106 return error(GL_INVALID_OPERATION);
1107 }
1108
1109 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1110 unsigned int q = log2(std::max(mWidth, mHeight));
1111 for (unsigned int i = 1; i <= q; i++)
1112 {
1113 if (mImageArray[i].surface != NULL)
1114 {
1115 mImageArray[i].surface->Release();
1116 mImageArray[i].surface = NULL;
1117 }
1118
1119 mImageArray[i].dirty = false;
1120
1121 mImageArray[i].format = mImageArray[0].format;
1122 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1123 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
1124 }
1125
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001126 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001127
1128 for (unsigned int i = 1; i <= q; i++)
1129 {
1130 IDirect3DSurface9 *upper = NULL;
1131 IDirect3DSurface9 *lower = NULL;
1132
1133 mTexture->GetSurfaceLevel(i-1, &upper);
1134 mTexture->GetSurfaceLevel(i, &lower);
1135
1136 if (upper != NULL && lower != NULL)
1137 {
1138 getBlitter()->boxFilter(upper, lower);
1139 }
1140
1141 if (upper != NULL) upper->Release();
1142 if (lower != NULL) lower->Release();
1143 }
1144}
1145
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001146Renderbuffer *Texture2D::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001147{
1148 if (target != GL_TEXTURE_2D)
1149 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001150 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001151 }
1152
1153 if (mColorbufferProxy == NULL)
1154 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001155 mColorbufferProxy = new Renderbuffer(id(), new TextureColorbufferProxy(this, target));
1156 mColorbufferProxy->addRef();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001157 }
1158
1159 return mColorbufferProxy;
1160}
1161
1162IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1163{
1164 ASSERT(target == GL_TEXTURE_2D);
1165
1166 needRenderTarget();
1167
1168 IDirect3DSurface9 *renderTarget = NULL;
1169 mTexture->GetSurfaceLevel(0, &renderTarget);
1170
1171 return renderTarget;
1172}
1173
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001174TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001175{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001176 mTexture = NULL;
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001177
1178 for (int i = 0; i < 6; i++)
1179 {
1180 mFaceProxies[i] = NULL;
1181 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001182}
1183
1184TextureCubeMap::~TextureCubeMap()
1185{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001186 for (int i = 0; i < 6; i++)
1187 {
1188 delete mFaceProxies[i];
1189 }
1190
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001191 if (mTexture)
1192 {
1193 mTexture->Release();
1194 mTexture = NULL;
1195 }
1196}
1197
1198GLenum TextureCubeMap::getTarget() const
1199{
1200 return GL_TEXTURE_CUBE_MAP;
1201}
1202
daniel@transgaming.com01868132010-08-24 19:21:17 +00001203GLenum TextureCubeMap::getFormat() const
1204{
1205 return mImageArray[0][0].format;
1206}
1207
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001208void 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 +00001209{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001210 setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001211}
1212
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001213void 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 +00001214{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001215 setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001216}
1217
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001218void 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 +00001219{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001220 setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001221}
1222
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001223void 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 +00001224{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001225 setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001226}
1227
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001228void 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 +00001229{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001230 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001231}
1232
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001233void 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 +00001234{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001235 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001236}
1237
daniel@transgaming.com01868132010-08-24 19:21:17 +00001238void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1239{
1240 redefineTexture(level, internalFormat, width);
1241
1242 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[faceIndex(face)][level]);
1243}
1244
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001245void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1246{
1247 int face = faceIndex(faceTarget);
1248
1249 ASSERT(mImageArray[face][level].surface != NULL);
1250
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001251 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001252 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001253 IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level);
1254 ASSERT(destLevel != NULL);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001255
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001256 if (destLevel != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001257 {
1258 Image *img = &mImageArray[face][level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001259
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001260 RECT sourceRect;
1261 sourceRect.left = xoffset;
1262 sourceRect.top = yoffset;
1263 sourceRect.right = xoffset + width;
1264 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001265
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001266 POINT destPoint;
1267 destPoint.x = xoffset;
1268 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001269
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001270 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001271 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001272
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001273 destLevel->Release();
1274
1275 img->dirty = false;
1276 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001277 }
1278}
1279
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001280void 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 +00001281{
daniel@transgaming.com31273552010-08-04 13:42:44 +00001282 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(face)][level]))
1283 {
1284 commitRect(face, level, xoffset, yoffset, width, height);
1285 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001286}
1287
daniel@transgaming.com01868132010-08-24 19:21:17 +00001288void TextureCubeMap::subImageCompressed(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1289{
1290 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(face)][level]))
1291 {
1292 commitRect(face, level, xoffset, yoffset, width, height);
1293 }
1294}
1295
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001296// 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 +00001297bool TextureCubeMap::isComplete() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001298{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001299 int size = mImageArray[0][0].width;
1300
1301 if (size <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001302 {
1303 return false;
1304 }
1305
1306 bool mipmapping;
1307
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001308 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001309 {
1310 case GL_NEAREST:
1311 case GL_LINEAR:
1312 mipmapping = false;
1313 break;
1314 case GL_NEAREST_MIPMAP_NEAREST:
1315 case GL_LINEAR_MIPMAP_NEAREST:
1316 case GL_NEAREST_MIPMAP_LINEAR:
1317 case GL_LINEAR_MIPMAP_LINEAR:
1318 mipmapping = true;
1319 break;
1320 default: UNREACHABLE();
1321 }
1322
1323 for (int face = 0; face < 6; face++)
1324 {
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001325 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001326 {
1327 return false;
1328 }
1329 }
1330
1331 if (mipmapping)
1332 {
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001333 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1334 {
1335 return false;
1336 }
1337
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001338 int q = log2(size);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001339
1340 for (int face = 0; face < 6; face++)
1341 {
1342 for (int level = 1; level <= q; level++)
1343 {
1344 if (mImageArray[face][level].format != mImageArray[0][0].format)
1345 {
1346 return false;
1347 }
1348
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001349 if (mImageArray[face][level].width != std::max(1, size >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001350 {
1351 return false;
1352 }
1353
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001354 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001355 }
1356 }
1357 }
1358
1359 return true;
1360}
1361
daniel@transgaming.com01868132010-08-24 19:21:17 +00001362bool TextureCubeMap::isCompressed() const
1363{
1364 return IsCompressed(getFormat());
1365}
1366
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001367// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001368IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001369{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001370 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001371 D3DFORMAT format = selectFormat(mImageArray[0][0].format);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001372
1373 IDirect3DCubeTexture9 *texture;
1374
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001375 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001376
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001377 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001378 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001379 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001380 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001381 }
1382
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001383 if (mTexture) mTexture->Release();
1384
1385 mTexture = texture;
1386 return mTexture;
1387}
1388
1389void TextureCubeMap::updateTexture()
1390{
1391 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001392
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001393 for (int face = 0; face < 6; face++)
1394 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001395 int levels = levelCount();
1396 for (int level = 0; level < levels; level++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001397 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001398 Image *img = &mImageArray[face][level];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001399
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001400 if (img->dirty)
1401 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001402 IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level);
1403 ASSERT(levelSurface != NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001404
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001405 if (levelSurface != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001406 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001407 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001408 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001409
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001410 levelSurface->Release();
1411
1412 img->dirty = false;
1413 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001414 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001415 }
1416 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001417}
1418
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001419IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
1420{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001421 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001422
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001423 if (mWidth != 0)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001424 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001425 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001426 IDirect3DDevice9 *device = getDevice();
1427 D3DFORMAT format = selectFormat(mImageArray[0][0].format);
1428
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001429 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001430
1431 if (FAILED(result))
1432 {
1433 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1434 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1435 }
1436
1437 if (mTexture != NULL)
1438 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001439 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001440 for (int f = 0; f < 6; f++)
1441 {
1442 for (int i = 0; i < levels; i++)
1443 {
1444 IDirect3DSurface9 *source;
1445 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
1446
1447 if (FAILED(result))
1448 {
1449 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1450
1451 texture->Release();
1452
1453 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1454 }
1455
1456 IDirect3DSurface9 *dest;
1457 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
1458
1459 if (FAILED(result))
1460 {
1461 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1462
1463 texture->Release();
1464 source->Release();
1465
1466 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1467 }
1468
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001469 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001470 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1471
1472 if (FAILED(result))
1473 {
1474 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1475
1476 texture->Release();
1477 source->Release();
1478 dest->Release();
1479
1480 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1481 }
1482 }
1483 }
1484 }
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001485 }
1486
1487 if (mTexture != NULL)
1488 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001489 mTexture->Release();
1490 }
1491
1492 mTexture = texture;
1493 return mTexture;
1494}
1495
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001496void 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 +00001497{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001498 redefineTexture(level, internalFormat, width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001499
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001500 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001501}
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001502
1503unsigned int TextureCubeMap::faceIndex(GLenum face)
1504{
1505 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1506 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1507 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1508 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1509 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1510
1511 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1512}
1513
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001514bool TextureCubeMap::dirtyImageData() const
1515{
1516 int q = log2(mWidth);
1517
1518 for (int f = 0; f < 6; f++)
1519 {
1520 for (int i = 0; i <= q; i++)
1521 {
1522 if (mImageArray[f][i].dirty) return true;
1523 }
1524 }
1525
1526 return false;
1527}
1528
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001529// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1530// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
1531// Call this when a particular level of the texture must be defined with a specific format, width and height.
1532//
1533// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
1534// a new size for the texture by working backwards from the given size.
1535bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
1536{
1537 // Are these settings compatible with level 0?
1538 bool sizeOkay = (mImageArray[0][0].width >> level == width);
1539
1540 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
1541
1542 if (!textureOkay)
1543 {
1544 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
1545 mImageArray[0][0].format, mImageArray[0][0].width,
1546 internalFormat, width);
1547
1548 // Purge all the levels and the texture.
1549 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
1550 {
1551 for (int f = 0; f < 6; f++)
1552 {
1553 if (mImageArray[f][i].surface != NULL)
1554 {
1555 mImageArray[f][i].dirty = false;
1556
1557 mImageArray[f][i].surface->Release();
1558 mImageArray[f][i].surface = NULL;
1559 }
1560 }
1561 }
1562
1563 if (mTexture != NULL)
1564 {
1565 mTexture->Release();
1566 mTexture = NULL;
1567 dropTexture();
1568 }
1569
1570 mWidth = width << level;
1571 mImageArray[0][0].width = width << level;
1572 mHeight = width << level;
1573 mImageArray[0][0].height = width << level;
1574
1575 mImageArray[0][0].format = internalFormat;
1576 }
1577
1578 return !textureOkay;
1579}
1580
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001581void 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 +00001582{
1583 unsigned int faceindex = faceIndex(face);
1584
1585 if (redefineTexture(level, internalFormat, width))
1586 {
1587 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001588 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001589 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001590 else
1591 {
1592 needRenderTarget();
1593 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001594
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001595 ASSERT(width == height);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001596
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001597 if (width > 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001598 {
1599 RECT sourceRect;
1600 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001601 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +00001602 sourceRect.top = y;
1603 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001604
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001605 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
1606
1607 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1608 dest->Release();
1609 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001610
1611 mImageArray[faceindex][level].width = width;
1612 mImageArray[faceindex][level].height = height;
1613 mImageArray[faceindex][level].format = internalFormat;
1614}
1615
1616IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(unsigned int faceIdentifier, unsigned int level)
1617{
1618 unsigned int faceIndex;
1619
1620 if (faceIdentifier < 6)
1621 {
1622 faceIndex = faceIdentifier;
1623 }
1624 else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
1625 {
1626 faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1627 }
1628 else
1629 {
1630 UNREACHABLE();
1631 faceIndex = 0;
1632 }
1633
1634 if (mTexture == NULL)
1635 {
1636 UNREACHABLE();
1637 return NULL;
1638 }
1639
1640 IDirect3DSurface9 *surface = NULL;
1641
1642 HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface);
1643
1644 return (SUCCEEDED(hr)) ? surface : NULL;
1645}
1646
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001647void 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 +00001648{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001649 GLsizei size = mImageArray[faceIndex(face)][level].width;
1650
1651 if (xoffset + width > size || yoffset + height > size)
1652 {
1653 return error(GL_INVALID_VALUE);
1654 }
1655
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001656 if (redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width))
1657 {
1658 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001659 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001660 }
1661 else
1662 {
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001663 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001664 }
1665
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001666 if (level < levelCount())
1667 {
1668 RECT sourceRect;
1669 sourceRect.left = x;
1670 sourceRect.right = x + width;
1671 sourceRect.top = y;
1672 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001673
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001674 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001675
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001676 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
1677 dest->Release();
1678 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001679}
1680
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001681bool TextureCubeMap::isCubeComplete() const
1682{
1683 if (mImageArray[0][0].width == 0)
1684 {
1685 return false;
1686 }
1687
1688 for (unsigned int f = 1; f < 6; f++)
1689 {
1690 if (mImageArray[f][0].width != mImageArray[0][0].width
1691 || mImageArray[f][0].format != mImageArray[0][0].format)
1692 {
1693 return false;
1694 }
1695 }
1696
1697 return true;
1698}
1699
1700void TextureCubeMap::generateMipmaps()
1701{
1702 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
1703 {
1704 return error(GL_INVALID_OPERATION);
1705 }
1706
1707 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1708 unsigned int q = log2(mImageArray[0][0].width);
1709 for (unsigned int f = 0; f < 6; f++)
1710 {
1711 for (unsigned int i = 1; i <= q; i++)
1712 {
1713 if (mImageArray[f][i].surface != NULL)
1714 {
1715 mImageArray[f][i].surface->Release();
1716 mImageArray[f][i].surface = NULL;
1717 }
1718
1719 mImageArray[f][i].dirty = false;
1720
1721 mImageArray[f][i].format = mImageArray[f][0].format;
1722 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
1723 mImageArray[f][i].height = mImageArray[f][i].width;
1724 }
1725 }
1726
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001727 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001728
1729 for (unsigned int f = 0; f < 6; f++)
1730 {
1731 for (unsigned int i = 1; i <= q; i++)
1732 {
1733 IDirect3DSurface9 *upper = getCubeMapSurface(f, i-1);
1734 IDirect3DSurface9 *lower = getCubeMapSurface(f, i);
1735
1736 if (upper != NULL && lower != NULL)
1737 {
1738 getBlitter()->boxFilter(upper, lower);
1739 }
1740
1741 if (upper != NULL) upper->Release();
1742 if (lower != NULL) lower->Release();
1743 }
1744 }
1745}
1746
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001747Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001748{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001749 if (!IsCubemapTextureTarget(target))
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001750 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001751 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001752 }
1753
1754 unsigned int face = faceIndex(target);
1755
1756 if (mFaceProxies[face] == NULL)
1757 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001758 mFaceProxies[face] = new Renderbuffer(id(), new TextureColorbufferProxy(this, target));
1759 mFaceProxies[face]->addRef();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001760 }
1761
1762 return mFaceProxies[face];
1763}
1764
1765IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
1766{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001767 ASSERT(IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001768
1769 needRenderTarget();
1770
1771 IDirect3DSurface9 *renderTarget = NULL;
1772 mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex(target)), 0, &renderTarget);
1773
1774 return renderTarget;
1775}
1776
1777Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
1778 : Colorbuffer(NULL), mTexture(texture), mTarget(target)
1779{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001780 ASSERT(target == GL_TEXTURE_2D || IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001781}
1782
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001783void Texture::TextureColorbufferProxy::addRef() const
1784{
1785 mTexture->addRef();
1786}
1787
1788void Texture::TextureColorbufferProxy::release() const
1789{
1790 mTexture->release();
1791}
1792
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001793IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
1794{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001795 if (mRenderTarget) mRenderTarget->Release();
1796
1797 mRenderTarget = mTexture->getRenderTarget(mTarget);
1798
1799 return mRenderTarget;
1800}
1801
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001802int Texture::TextureColorbufferProxy::getWidth() const
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001803{
daniel@transgaming.com866f3182010-05-20 19:28:22 +00001804 return mTexture->getWidth();
1805}
1806
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001807int Texture::TextureColorbufferProxy::getHeight() const
daniel@transgaming.com866f3182010-05-20 19:28:22 +00001808{
1809 return mTexture->getHeight();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001810}
1811
daniel@transgaming.com01868132010-08-24 19:21:17 +00001812GLenum Texture::TextureColorbufferProxy::getFormat() const
1813{
1814 return mTexture->getFormat();
1815}
1816
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001817}