blob: 7c040f8327a125e3d2c850f9df38b99e2ae8e369 [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
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +000013#include <d3dx9tex.h>
14
daniel@transgaming.com16973022010-03-11 19:22:19 +000015#include <algorithm>
16
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000017#include "common/debug.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000018
19#include "libGLESv2/main.h"
20#include "libGLESv2/mathutil.h"
21#include "libGLESv2/utilities.h"
22#include "libGLESv2/Blit.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000023
24namespace gl
25{
daniel@transgaming.com842f7a42010-03-21 04:31:03 +000026
27Texture::Image::Image()
daniel@transgaming.com01868132010-08-24 19:21:17 +000028 : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +000029{
30}
31
32Texture::Image::~Image()
33{
34 if (surface) surface->Release();
35}
36
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000037Texture::Texture(GLuint id) : RefCountObject(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000038{
39 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
40 mMagFilter = GL_LINEAR;
41 mWrapS = GL_REPEAT;
42 mWrapT = GL_REPEAT;
daniel@transgaming.com29d27002010-03-11 19:41:22 +000043
daniel@transgaming.com31273552010-08-04 13:42:44 +000044 mWidth = 0;
45 mHeight = 0;
46
daniel@transgaming.com00c75962010-03-11 20:36:15 +000047 mDirtyMetaData = true;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000048 mDirty = true;
daniel@transgaming.com93a81472010-04-20 18:52:58 +000049 mIsRenderable = false;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +000050 mType = GL_UNSIGNED_BYTE;
daniel@transgaming.com0a311a42010-05-17 09:58:33 +000051 mBaseTexture = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000052}
53
54Texture::~Texture()
55{
56}
57
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000058Blit *Texture::getBlitter()
59{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000060 Context *context = getContext();
61 return context->getBlitter();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000062}
63
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000064// Returns true on successful filter state update (valid enum parameter)
65bool Texture::setMinFilter(GLenum filter)
66{
67 switch (filter)
68 {
69 case GL_NEAREST:
70 case GL_LINEAR:
71 case GL_NEAREST_MIPMAP_NEAREST:
72 case GL_LINEAR_MIPMAP_NEAREST:
73 case GL_NEAREST_MIPMAP_LINEAR:
74 case GL_LINEAR_MIPMAP_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000075 {
76 if (mMinFilter != filter)
77 {
78 mMinFilter = filter;
79 mDirty = true;
80 }
81 return true;
82 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000083 default:
84 return false;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +000085 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000086}
87
88// Returns true on successful filter state update (valid enum parameter)
89bool Texture::setMagFilter(GLenum filter)
90{
91 switch (filter)
92 {
93 case GL_NEAREST:
94 case GL_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000095 {
96 if (mMagFilter != filter)
97 {
98 mMagFilter = filter;
99 mDirty = true;
100 }
101 return true;
102 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000103 default:
104 return false;
105 }
106}
107
108// Returns true on successful wrap state update (valid enum parameter)
109bool Texture::setWrapS(GLenum wrap)
110{
111 switch (wrap)
112 {
113 case GL_REPEAT:
114 case GL_CLAMP_TO_EDGE:
115 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000116 {
117 if (mWrapS != wrap)
118 {
119 mWrapS = wrap;
120 mDirty = true;
121 }
122 return true;
123 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000124 default:
125 return false;
126 }
127}
128
129// Returns true on successful wrap state update (valid enum parameter)
130bool Texture::setWrapT(GLenum wrap)
131{
132 switch (wrap)
133 {
134 case GL_REPEAT:
135 case GL_CLAMP_TO_EDGE:
136 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000137 {
138 if (mWrapT != wrap)
139 {
140 mWrapT = wrap;
141 mDirty = true;
142 }
143 return true;
144 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000145 default:
146 return false;
147 }
148}
149
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000150GLenum Texture::getMinFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000151{
152 return mMinFilter;
153}
154
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000155GLenum Texture::getMagFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000156{
157 return mMagFilter;
158}
159
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000160GLenum Texture::getWrapS() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000161{
162 return mWrapS;
163}
164
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000165GLenum Texture::getWrapT() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000166{
167 return mWrapT;
168}
169
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000170GLuint Texture::getWidth() const
171{
172 return mWidth;
173}
174
175GLuint Texture::getHeight() const
176{
177 return mHeight;
178}
179
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000180bool Texture::isFloatingPoint() const
181{
182 return (mType == GL_FLOAT || mType == GL_HALF_FLOAT_OES);
183}
184
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +0000185bool Texture::isRenderableFormat() const
186{
187 D3DFORMAT format = getD3DFormat();
188
189 switch(format)
190 {
191 case D3DFMT_L8:
192 case D3DFMT_A8L8:
193 case D3DFMT_DXT1:
194 return false;
195 case D3DFMT_A8R8G8B8:
apatrick@chromium.org9c857952010-11-16 18:27:58 +0000196 case D3DFMT_X8R8G8B8:
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +0000197 case D3DFMT_A16B16G16R16F:
198 case D3DFMT_A32B32G32R32F:
199 return true;
200 default:
201 UNREACHABLE();
202 }
203
204 return false;
205}
206
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000207// Selects an internal Direct3D 9 format for storing an Image
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000208D3DFORMAT Texture::selectFormat(GLenum format, GLenum type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000209{
daniel@transgaming.com01868132010-08-24 19:21:17 +0000210 if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
211 format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
212 {
213 return D3DFMT_DXT1;
214 }
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000215 else if (type == GL_FLOAT)
216 {
217 return D3DFMT_A32B32G32R32F;
218 }
219 else if (type == GL_HALF_FLOAT_OES)
220 {
221 return D3DFMT_A16B16G16R16F;
222 }
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000223 else if (type == GL_UNSIGNED_BYTE)
daniel@transgaming.com01868132010-08-24 19:21:17 +0000224 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000225 if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
226 {
227 return D3DFMT_L8;
228 }
229 else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
230 {
231 return D3DFMT_A8L8;
232 }
apatrick@chromium.org9c857952010-11-16 18:27:58 +0000233 else if (format == GL_RGB)
234 {
235 return D3DFMT_X8R8G8B8;
236 }
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000237
daniel@transgaming.com01868132010-08-24 19:21:17 +0000238 return D3DFMT_A8R8G8B8;
239 }
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000240
241 return D3DFMT_A8R8G8B8;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000242}
243
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000244// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000245// into the target pixel rectangle at output with outputPitch bytes in between each line.
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000246void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000247 GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000248{
daniel@transgaming.com713914b2010-05-04 03:35:17 +0000249 GLsizei inputPitch = ComputePitch(width, format, type, unpackAlignment);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000250
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000251 switch (type)
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000252 {
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000253 case GL_UNSIGNED_BYTE:
254 switch (format)
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000255 {
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000256 case GL_ALPHA:
257 loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
258 break;
259 case GL_LUMINANCE:
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000260 loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000261 break;
262 case GL_LUMINANCE_ALPHA:
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000263 loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000264 break;
265 case GL_RGB:
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000266 loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
267 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000268 case GL_RGBA:
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000269 loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
270 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000271 case GL_BGRA_EXT:
272 loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000273 break;
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000274 default: UNREACHABLE();
275 }
276 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000277 case GL_UNSIGNED_SHORT_5_6_5:
278 switch (format)
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000279 {
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000280 case GL_RGB:
281 loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000282 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000283 default: UNREACHABLE();
284 }
285 break;
286 case GL_UNSIGNED_SHORT_4_4_4_4:
287 switch (format)
288 {
289 case GL_RGBA:
290 loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
291 break;
292 default: UNREACHABLE();
293 }
294 break;
295 case GL_UNSIGNED_SHORT_5_5_5_1:
296 switch (format)
297 {
298 case GL_RGBA:
299 loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
300 break;
301 default: UNREACHABLE();
302 }
303 break;
304 case GL_FLOAT:
305 switch (format)
306 {
307 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
308 case GL_ALPHA:
309 loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
310 break;
311 case GL_LUMINANCE:
312 loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
313 break;
314 case GL_LUMINANCE_ALPHA:
315 loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
316 break;
317 case GL_RGB:
318 loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
319 break;
320 case GL_RGBA:
321 loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
322 break;
323 default: UNREACHABLE();
324 }
325 break;
326 case GL_HALF_FLOAT_OES:
327 switch (format)
328 {
329 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
330 case GL_ALPHA:
331 loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
332 break;
333 case GL_LUMINANCE:
334 loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
335 break;
336 case GL_LUMINANCE_ALPHA:
337 loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
338 break;
339 case GL_RGB:
340 loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
341 break;
342 case GL_RGBA:
343 loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
344 break;
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000345 default: UNREACHABLE();
346 }
347 break;
348 default: UNREACHABLE();
349 }
350}
351
352void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
353 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
354{
355 const unsigned char *source = NULL;
356 unsigned char *dest = NULL;
357
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000358 for (int y = 0; y < height; y++)
359 {
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000360 source = static_cast<const unsigned char*>(input) + y * inputPitch;
361 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000362 for (int x = 0; x < width; x++)
363 {
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000364 dest[4 * x + 0] = 0;
365 dest[4 * x + 1] = 0;
366 dest[4 * x + 2] = 0;
367 dest[4 * x + 3] = source[x];
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000368 }
369 }
370}
371
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000372void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
373 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
374{
375 const float *source = NULL;
376 float *dest = NULL;
377
378 for (int y = 0; y < height; y++)
379 {
380 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
381 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
382 for (int x = 0; x < width; x++)
383 {
384 dest[4 * x + 0] = 0;
385 dest[4 * x + 1] = 0;
386 dest[4 * x + 2] = 0;
387 dest[4 * x + 3] = source[x];
388 }
389 }
390}
391
392void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
393 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
394{
395 const unsigned short *source = NULL;
396 unsigned short *dest = NULL;
397
398 for (int y = 0; y < height; y++)
399 {
400 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
401 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
402 for (int x = 0; x < width; x++)
403 {
404 dest[4 * x + 0] = 0;
405 dest[4 * x + 1] = 0;
406 dest[4 * x + 2] = 0;
407 dest[4 * x + 3] = source[x];
408 }
409 }
410}
411
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000412void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000413 size_t inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000414{
baustin@google.comad5df072011-01-06 21:07:46 +0000415 const int destBytesPerPixel = native? 1: 4;
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000416 const unsigned char *source = NULL;
417 unsigned char *dest = NULL;
418
419 for (int y = 0; y < height; y++)
420 {
421 source = static_cast<const unsigned char*>(input) + y * inputPitch;
baustin@google.comad5df072011-01-06 21:07:46 +0000422 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000423
424 if (!native) // BGRA8 destination format
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000425 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000426 for (int x = 0; x < width; x++)
427 {
428 dest[4 * x + 0] = source[x];
429 dest[4 * x + 1] = source[x];
430 dest[4 * x + 2] = source[x];
431 dest[4 * x + 3] = 0xFF;
432 }
433 }
434 else // L8 destination format
435 {
436 memcpy(dest, source, width);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000437 }
438 }
439}
440
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000441void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
442 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
443{
444 const float *source = NULL;
445 float *dest = NULL;
446
447 for (int y = 0; y < height; y++)
448 {
449 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
450 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
451 for (int x = 0; x < width; x++)
452 {
453 dest[4 * x + 0] = source[x];
454 dest[4 * x + 1] = source[x];
455 dest[4 * x + 2] = source[x];
456 dest[4 * x + 3] = 1.0f;
457 }
458 }
459}
460
461void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
462 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
463{
464 const unsigned short *source = NULL;
465 unsigned short *dest = NULL;
466
467 for (int y = 0; y < height; y++)
468 {
469 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
470 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
471 for (int x = 0; x < width; x++)
472 {
473 dest[4 * x + 0] = source[x];
474 dest[4 * x + 1] = source[x];
475 dest[4 * x + 2] = source[x];
476 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
477 }
478 }
479}
480
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000481void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000482 size_t inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000483{
baustin@google.comad5df072011-01-06 21:07:46 +0000484 const int destBytesPerPixel = native? 2: 4;
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000485 const unsigned char *source = NULL;
486 unsigned char *dest = NULL;
487
488 for (int y = 0; y < height; y++)
489 {
490 source = static_cast<const unsigned char*>(input) + y * inputPitch;
baustin@google.comad5df072011-01-06 21:07:46 +0000491 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000492
493 if (!native) // BGRA8 destination format
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000494 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000495 for (int x = 0; x < width; x++)
496 {
497 dest[4 * x + 0] = source[2*x+0];
498 dest[4 * x + 1] = source[2*x+0];
499 dest[4 * x + 2] = source[2*x+0];
500 dest[4 * x + 3] = source[2*x+1];
501 }
502 }
503 else
504 {
505 memcpy(dest, source, width * 2);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000506 }
507 }
508}
509
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000510void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
511 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
512{
513 const float *source = NULL;
514 float *dest = NULL;
515
516 for (int y = 0; y < height; y++)
517 {
518 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
519 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
520 for (int x = 0; x < width; x++)
521 {
522 dest[4 * x + 0] = source[2*x+0];
523 dest[4 * x + 1] = source[2*x+0];
524 dest[4 * x + 2] = source[2*x+0];
525 dest[4 * x + 3] = source[2*x+1];
526 }
527 }
528}
529
530void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
531 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
532{
533 const unsigned short *source = NULL;
534 unsigned short *dest = NULL;
535
536 for (int y = 0; y < height; y++)
537 {
538 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
539 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
540 for (int x = 0; x < width; x++)
541 {
542 dest[4 * x + 0] = source[2*x+0];
543 dest[4 * x + 1] = source[2*x+0];
544 dest[4 * x + 2] = source[2*x+0];
545 dest[4 * x + 3] = source[2*x+1];
546 }
547 }
548}
549
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000550void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
551 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
552{
553 const unsigned char *source = NULL;
554 unsigned char *dest = NULL;
555
556 for (int y = 0; y < height; y++)
557 {
558 source = static_cast<const unsigned char*>(input) + y * inputPitch;
559 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
560 for (int x = 0; x < width; x++)
561 {
562 dest[4 * x + 0] = source[x * 3 + 2];
563 dest[4 * x + 1] = source[x * 3 + 1];
564 dest[4 * x + 2] = source[x * 3 + 0];
565 dest[4 * x + 3] = 0xFF;
566 }
567 }
568}
569
570void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
571 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
572{
573 const unsigned short *source = NULL;
574 unsigned char *dest = NULL;
575
576 for (int y = 0; y < height; y++)
577 {
578 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
579 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
580 for (int x = 0; x < width; x++)
581 {
582 unsigned short rgba = source[x];
583 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
584 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
585 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
586 dest[4 * x + 3] = 0xFF;
587 }
588 }
589}
590
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000591void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
592 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
593{
594 const float *source = NULL;
595 float *dest = NULL;
596
597 for (int y = 0; y < height; y++)
598 {
599 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
600 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
601 for (int x = 0; x < width; x++)
602 {
603 dest[4 * x + 0] = source[x * 3 + 0];
604 dest[4 * x + 1] = source[x * 3 + 1];
605 dest[4 * x + 2] = source[x * 3 + 2];
606 dest[4 * x + 3] = 1.0f;
607 }
608 }
609}
610
611void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
612 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
613{
614 const unsigned short *source = NULL;
615 unsigned short *dest = NULL;
616
617 for (int y = 0; y < height; y++)
618 {
619 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
620 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
621 for (int x = 0; x < width; x++)
622 {
623 dest[4 * x + 0] = source[x * 3 + 0];
624 dest[4 * x + 1] = source[x * 3 + 1];
625 dest[4 * x + 2] = source[x * 3 + 2];
626 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
627 }
628 }
629}
630
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000631void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
632 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
633{
634 const unsigned char *source = NULL;
635 unsigned char *dest = NULL;
636
637 for (int y = 0; y < height; y++)
638 {
639 source = static_cast<const unsigned char*>(input) + y * inputPitch;
640 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
641 for (int x = 0; x < width; x++)
642 {
643 dest[4 * x + 0] = source[x * 4 + 2];
644 dest[4 * x + 1] = source[x * 4 + 1];
645 dest[4 * x + 2] = source[x * 4 + 0];
646 dest[4 * x + 3] = source[x * 4 + 3];
647 }
648 }
649}
650
651void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
652 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
653{
654 const unsigned short *source = NULL;
655 unsigned char *dest = NULL;
656
657 for (int y = 0; y < height; y++)
658 {
659 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
660 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
661 for (int x = 0; x < width; x++)
662 {
663 unsigned short rgba = source[x];
664 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
665 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
666 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
667 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
668 }
669 }
670}
671
672void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
673 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
674{
675 const unsigned short *source = NULL;
676 unsigned char *dest = NULL;
677
678 for (int y = 0; y < height; y++)
679 {
680 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
681 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
682 for (int x = 0; x < width; x++)
683 {
684 unsigned short rgba = source[x];
685 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
686 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
687 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
688 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
689 }
690 }
691}
692
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000693void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
694 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
695{
696 const float *source = NULL;
697 float *dest = NULL;
698
699 for (int y = 0; y < height; y++)
700 {
701 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
702 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
703 memcpy(dest, source, width * 16);
704 }
705}
706
707void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
708 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
709{
710 const unsigned char *source = NULL;
711 unsigned char *dest = NULL;
712
713 for (int y = 0; y < height; y++)
714 {
715 source = static_cast<const unsigned char*>(input) + y * inputPitch;
716 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
717 memcpy(dest, source, width * 8);
718 }
719}
720
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000721void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
722 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
723{
724 const unsigned char *source = NULL;
725 unsigned char *dest = NULL;
726
727 for (int y = 0; y < height; y++)
728 {
729 source = static_cast<const unsigned char*>(input) + y * inputPitch;
730 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
731 memcpy(dest, source, width*4);
732 }
733}
734
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000735void Texture::createSurface(GLsizei width, GLsizei height, GLenum format, GLenum type, Image *img)
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000736{
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000737 IDirect3DTexture9 *newTexture = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000738 IDirect3DSurface9 *newSurface = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000739
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000740 if (width != 0 && height != 0)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000741 {
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000742 int levelToFetch = 0;
743 GLsizei requestWidth = width;
744 GLsizei requestHeight = height;
745 if (IsCompressed(format) && (width % 4 != 0 || height % 4 != 0))
746 {
747 bool isMult4 = false;
748 int upsampleCount = 0;
749 while (!isMult4)
750 {
751 requestWidth <<= 1;
752 requestHeight <<= 1;
753 upsampleCount++;
754 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
755 {
756 isMult4 = true;
757 }
758 }
759 levelToFetch = upsampleCount;
760 }
761
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000762 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, selectFormat(format, type),
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000763 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000764
765 if (FAILED(result))
766 {
767 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
768 return error(GL_OUT_OF_MEMORY);
769 }
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000770
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000771 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000772 newTexture->Release();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000773 }
774
775 if (img->surface) img->surface->Release();
776 img->surface = newSurface;
777
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000778 img->width = width;
779 img->height = height;
780 img->format = format;
daniel@transgaming.com01868132010-08-24 19:21:17 +0000781}
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000782
daniel@transgaming.com01868132010-08-24 19:21:17 +0000783void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
784{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000785 createSurface(width, height, format, type, img);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000786
787 if (pixels != NULL && img->surface != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000788 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000789 D3DSURFACE_DESC description;
790 img->surface->GetDesc(&description);
791
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000792 D3DLOCKED_RECT locked;
daniel@transgaming.com01868132010-08-24 19:21:17 +0000793 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000794
795 ASSERT(SUCCEEDED(result));
796
797 if (SUCCEEDED(result))
798 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000799 loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000800 img->surface->UnlockRect();
801 }
802
803 img->dirty = true;
804 }
805
806 mDirtyMetaData = true;
807}
808
809void Texture::setCompressedImage(GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
810{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000811 createSurface(width, height, format, GL_UNSIGNED_BYTE, img);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000812
813 if (pixels != NULL && img->surface != NULL)
814 {
815 D3DLOCKED_RECT locked;
816 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
817
818 ASSERT(SUCCEEDED(result));
819
820 if (SUCCEEDED(result))
821 {
822 memcpy(locked.pBits, pixels, imageSize);
823 img->surface->UnlockRect();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000824 }
825
826 img->dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000827 }
828
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000829 mDirtyMetaData = true;
830}
831
daniel@transgaming.com31273552010-08-04 13:42:44 +0000832bool 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 +0000833{
daniel@transgaming.com31273552010-08-04 13:42:44 +0000834 if (width + xoffset > img->width || height + yoffset > img->height)
835 {
836 error(GL_INVALID_VALUE);
837 return false;
838 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000839
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000840 if (!img->surface)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000841 {
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000842 createSurface(img->width, img->height, format, type, img);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000843 }
844
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000845 if (pixels != NULL && img->surface != NULL)
846 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000847 D3DSURFACE_DESC description;
848 img->surface->GetDesc(&description);
849
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000850 D3DLOCKED_RECT locked;
851 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
852
853 ASSERT(SUCCEEDED(result));
854
855 if (SUCCEEDED(result))
856 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000857 loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000858 img->surface->UnlockRect();
859 }
860
861 img->dirty = true;
862 }
863
daniel@transgaming.com31273552010-08-04 13:42:44 +0000864 return true;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000865}
866
daniel@transgaming.com01868132010-08-24 19:21:17 +0000867bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
868{
869 if (width + xoffset > img->width || height + yoffset > img->height)
870 {
871 error(GL_INVALID_VALUE);
872 return false;
873 }
874
875 if (format != getFormat())
876 {
877 error(GL_INVALID_OPERATION);
878 return false;
879 }
880
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000881 if (!img->surface)
daniel@transgaming.com01868132010-08-24 19:21:17 +0000882 {
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000883 createSurface(img->width, img->height, format, GL_UNSIGNED_BYTE, img);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000884 }
885
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000886 if (pixels != NULL && img->surface != NULL)
887 {
888 RECT updateRegion;
889 updateRegion.left = xoffset;
890 updateRegion.right = xoffset + width;
891 updateRegion.bottom = yoffset + height;
892 updateRegion.top = yoffset;
893
894 D3DLOCKED_RECT locked;
895 HRESULT result = img->surface->LockRect(&locked, &updateRegion, 0);
896
897 ASSERT(SUCCEEDED(result));
898
899 if (SUCCEEDED(result))
900 {
901 GLsizei inputPitch = ComputeCompressedPitch(width, format);
902 int rows = imageSize / inputPitch;
903 for (int i = 0; i < rows; ++i)
904 {
905 memcpy((void*)((BYTE*)locked.pBits + i * locked.Pitch), (void*)((BYTE*)pixels + i * inputPitch), inputPitch);
906 }
907 img->surface->UnlockRect();
908 }
909
910 img->dirty = true;
911 }
912
daniel@transgaming.com01868132010-08-24 19:21:17 +0000913 return true;
914}
915
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +0000916// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats
917void Texture::copyNonRenderable(Image *image, GLenum internalFormat, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
918{
919 IDirect3DDevice9 *device = getDevice();
920 IDirect3DSurface9 *surface = NULL;
921 D3DSURFACE_DESC description;
922 renderTarget->GetDesc(&description);
923
924 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
925
926 if (!SUCCEEDED(result))
927 {
928 ERR("Could not create matching destination surface.");
929 return error(GL_OUT_OF_MEMORY);
930 }
931
932 result = device->GetRenderTargetData(renderTarget, surface);
933
934 if (!SUCCEEDED(result))
935 {
936 ERR("GetRenderTargetData unexpectedly failed.");
937 surface->Release();
938 return error(GL_OUT_OF_MEMORY);
939 }
940
941 D3DLOCKED_RECT sourceLock = {0};
942 RECT sourceRect = {x, y, x + width, y + height};
943 result = surface->LockRect(&sourceLock, &sourceRect, 0);
944
945 if (FAILED(result))
946 {
947 ERR("Failed to lock the source surface (rectangle might be invalid).");
948 surface->UnlockRect();
949 surface->Release();
950 return error(GL_OUT_OF_MEMORY);
951 }
952
953 if (!image->surface)
954 {
955 createSurface(width, height, internalFormat, mType, image);
956 }
957
958 if (image->surface == NULL)
959 {
960 ERR("Failed to create an image surface.");
961 surface->UnlockRect();
962 surface->Release();
963 return error(GL_OUT_OF_MEMORY);
964 }
965
966 D3DLOCKED_RECT destLock = {0};
967 RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height};
968 result = image->surface->LockRect(&destLock, &destRect, 0);
969
970 if (FAILED(result))
971 {
972 ERR("Failed to lock the destination surface (rectangle might be invalid).");
973 surface->UnlockRect();
974 surface->Release();
975 return error(GL_OUT_OF_MEMORY);
976 }
977
978 if (destLock.pBits && sourceLock.pBits)
979 {
980 unsigned char *source = (unsigned char*)sourceLock.pBits;
981 unsigned char *dest = (unsigned char*)destLock.pBits;
982
983 switch (description.Format)
984 {
985 case D3DFMT_X8R8G8B8:
986 case D3DFMT_A8R8G8B8:
987 switch(getD3DFormat())
988 {
989 case D3DFMT_L8:
990 for(int y = 0; y < height; y++)
991 {
daniel@transgaming.com17767ce2010-12-17 15:57:41 +0000992 for(int x = 0; x < width; x++)
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +0000993 {
994 dest[x] = source[x * 4 + 2];
995 }
996
997 source += sourceLock.Pitch;
998 dest += destLock.Pitch;
999 }
1000 break;
1001 case D3DFMT_A8L8:
1002 for(int y = 0; y < height; y++)
1003 {
daniel@transgaming.com17767ce2010-12-17 15:57:41 +00001004 for(int x = 0; x < width; x++)
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001005 {
1006 dest[x * 2 + 0] = source[x * 4 + 2];
1007 dest[x * 2 + 1] = source[x * 4 + 3];
1008 }
1009
1010 source += sourceLock.Pitch;
1011 dest += destLock.Pitch;
1012 }
1013 break;
1014 default:
1015 UNREACHABLE();
1016 }
1017 break;
daniel@transgaming.comfe5141e2010-10-18 12:18:12 +00001018 case D3DFMT_R5G6B5:
1019 switch(getD3DFormat())
1020 {
1021 case D3DFMT_L8:
1022 for(int y = 0; y < height; y++)
1023 {
daniel@transgaming.com17767ce2010-12-17 15:57:41 +00001024 for(int x = 0; x < width; x++)
daniel@transgaming.comfe5141e2010-10-18 12:18:12 +00001025 {
1026 unsigned char red = source[x * 2 + 1] & 0xF8;
1027 dest[x] = red | (red >> 5);
1028 }
1029
1030 source += sourceLock.Pitch;
1031 dest += destLock.Pitch;
1032 }
1033 break;
1034 default:
1035 UNREACHABLE();
1036 }
1037 break;
daniel@transgaming.com17767ce2010-12-17 15:57:41 +00001038 case D3DFMT_A1R5G5B5:
1039 switch(getD3DFormat())
1040 {
1041 case D3DFMT_L8:
1042 for(int y = 0; y < height; y++)
1043 {
1044 for(int x = 0; x < width; x++)
1045 {
1046 unsigned char red = source[x * 2 + 1] & 0x7C;
1047 dest[x] = (red << 1) | (red >> 4);
1048 }
1049
1050 source += sourceLock.Pitch;
1051 dest += destLock.Pitch;
1052 }
1053 break;
1054 case D3DFMT_A8L8:
1055 for(int y = 0; y < height; y++)
1056 {
1057 for(int x = 0; x < width; x++)
1058 {
1059 unsigned char red = source[x * 2 + 1] & 0x7C;
1060 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1061 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1062 }
1063
1064 source += sourceLock.Pitch;
1065 dest += destLock.Pitch;
1066 }
1067 break;
1068 default:
1069 UNREACHABLE();
1070 }
1071 break;
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001072 default:
1073 UNREACHABLE();
1074 }
1075
1076 image->dirty = true;
1077 mDirtyMetaData = true;
1078 }
1079
1080 image->surface->UnlockRect();
1081 surface->UnlockRect();
1082 surface->Release();
1083}
1084
enne@chromium.org0fa74632010-09-21 16:18:52 +00001085D3DFORMAT Texture::getD3DFormat() const
1086{
1087 return selectFormat(getFormat(), mType);
1088}
1089
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001090IDirect3DBaseTexture9 *Texture::getTexture()
1091{
1092 if (!isComplete())
1093 {
1094 return NULL;
1095 }
1096
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001097 if (mDirtyMetaData)
1098 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001099 mBaseTexture = createTexture();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001100 mIsRenderable = false;
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001101 }
1102
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001103 if (mDirtyMetaData || dirtyImageData())
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001104 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001105 updateTexture();
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001106 }
1107
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001108 mDirtyMetaData = false;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001109 ASSERT(!dirtyImageData());
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001110
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001111 return mBaseTexture;
1112}
1113
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00001114bool Texture::isDirty() const
1115{
1116 return (mDirty || mDirtyMetaData || dirtyImageData());
1117}
1118
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001119// Returns the top-level texture surface as a render target
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001120void Texture::needRenderTarget()
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001121{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001122 if (!mIsRenderable)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001123 {
1124 mBaseTexture = convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001125 mIsRenderable = true;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001126 }
1127
1128 if (dirtyImageData())
1129 {
1130 updateTexture();
1131 }
1132
1133 mDirtyMetaData = false;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001134}
1135
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001136void Texture::dropTexture()
1137{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001138 if (mBaseTexture)
1139 {
1140 mBaseTexture = NULL;
1141 }
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001142
1143 mIsRenderable = false;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001144}
1145
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001146void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001147{
1148 mBaseTexture = newTexture;
1149 mDirtyMetaData = false;
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001150 mIsRenderable = renderable;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00001151 mDirty = true;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001152}
1153
1154
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001155GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1156{
1157 if (isPow2(width) && isPow2(height))
1158 {
1159 return maxlevel;
1160 }
1161 else
1162 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001163 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1164 return 1;
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001165 }
1166}
1167
1168GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1169{
1170 return creationLevels(size, size, maxlevel);
1171}
1172
1173int Texture::levelCount() const
1174{
1175 return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
1176}
1177
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00001178bool Texture::isRenderable() const
1179{
1180 return mIsRenderable;
1181}
1182
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001183Texture2D::Texture2D(GLuint id) : Texture(id)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001184{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001185 mTexture = NULL;
1186}
1187
1188Texture2D::~Texture2D()
1189{
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001190 mColorbufferProxy.set(NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001191
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001192 if (mTexture)
1193 {
1194 mTexture->Release();
1195 mTexture = NULL;
1196 }
1197}
1198
1199GLenum Texture2D::getTarget() const
1200{
1201 return GL_TEXTURE_2D;
1202}
1203
daniel@transgaming.com01868132010-08-24 19:21:17 +00001204GLenum Texture2D::getFormat() const
1205{
1206 return mImageArray[0].format;
1207}
1208
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001209// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1210// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
1211// Call this when a particular level of the texture must be defined with a specific format, width and height.
1212//
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +00001213// Returns true if the existing texture was unsuitable and had to be destroyed. If so, it will also set
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001214// a new height and width for the texture by working backwards from the given width and height.
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001215bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001216{
1217 bool widthOkay = (mWidth >> level == width);
1218 bool heightOkay = (mHeight >> level == height);
1219
1220 bool sizeOkay = ((widthOkay && heightOkay)
1221 || (widthOkay && mHeight >> level == 0 && height == 1)
1222 || (heightOkay && mWidth >> level == 0 && width == 1));
1223
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001224 bool typeOkay = (type == mType);
1225
1226 bool textureOkay = (sizeOkay && typeOkay && internalFormat == mImageArray[0].format);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001227
1228 if (!textureOkay)
1229 {
1230 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
1231 mImageArray[0].format, mWidth, mHeight,
1232 internalFormat, width, height);
1233
1234 // Purge all the levels and the texture.
1235
daniel@transgaming.com5d752f22010-10-07 13:37:20 +00001236 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001237 {
1238 if (mImageArray[i].surface != NULL)
1239 {
1240 mImageArray[i].dirty = false;
1241
1242 mImageArray[i].surface->Release();
1243 mImageArray[i].surface = NULL;
1244 }
1245 }
1246
1247 if (mTexture != NULL)
1248 {
1249 mTexture->Release();
1250 mTexture = NULL;
1251 dropTexture();
1252 }
1253
1254 mWidth = width << level;
1255 mHeight = height << level;
1256 mImageArray[0].format = internalFormat;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001257 mType = type;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001258 }
1259
1260 return !textureOkay;
1261}
1262
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001263void 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 +00001264{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001265 redefineTexture(level, internalFormat, width, height, type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001266
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001267 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001268}
1269
daniel@transgaming.com01868132010-08-24 19:21:17 +00001270void Texture2D::setCompressedImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1271{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001272 redefineTexture(level, internalFormat, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.com01868132010-08-24 19:21:17 +00001273
1274 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[level]);
1275}
1276
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001277void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1278{
1279 ASSERT(mImageArray[level].surface != NULL);
1280
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001281 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001282 {
1283 IDirect3DSurface9 *destLevel = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001284 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001285
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001286 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001287
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001288 if (SUCCEEDED(result))
1289 {
1290 Image *img = &mImageArray[level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001291
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001292 RECT sourceRect;
1293 sourceRect.left = xoffset;
1294 sourceRect.top = yoffset;
1295 sourceRect.right = xoffset + width;
1296 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001297
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001298 POINT destPoint;
1299 destPoint.x = xoffset;
1300 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001301
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001302 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
1303 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001304
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001305 destLevel->Release();
1306
1307 img->dirty = false;
1308 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001309 }
1310}
1311
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001312void 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 +00001313{
daniel@transgaming.com31273552010-08-04 13:42:44 +00001314 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1315 {
1316 commitRect(level, xoffset, yoffset, width, height);
1317 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001318}
1319
daniel@transgaming.com01868132010-08-24 19:21:17 +00001320void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1321{
1322 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1323 {
1324 commitRect(level, xoffset, yoffset, width, height);
1325 }
1326}
1327
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001328void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001329{
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001330 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1331
1332 if (!renderTarget)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001333 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001334 ERR("Failed to retrieve the render target.");
1335 return error(GL_OUT_OF_MEMORY);
1336 }
1337
1338 bool redefined = redefineTexture(level, internalFormat, width, height, mType);
1339
1340 if (!isRenderableFormat())
1341 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001342 copyNonRenderable(&mImageArray[level], internalFormat, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001343 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001344 else
1345 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001346 if (redefined)
1347 {
1348 convertToRenderTarget();
1349 pushTexture(mTexture, true);
1350 }
1351 else
1352 {
1353 needRenderTarget();
1354 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001355
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001356 if (width != 0 && height != 0 && level < levelCount())
1357 {
1358 RECT sourceRect;
1359 sourceRect.left = x;
1360 sourceRect.right = x + width;
1361 sourceRect.top = y;
1362 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001363
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001364 IDirect3DSurface9 *dest;
1365 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001366
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001367 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1368 dest->Release();
1369 }
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001370 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001371
1372 mImageArray[level].width = width;
1373 mImageArray[level].height = height;
1374 mImageArray[level].format = internalFormat;
1375}
1376
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001377void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001378{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001379 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1380 {
1381 return error(GL_INVALID_VALUE);
1382 }
1383
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001384 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1385
1386 if (!renderTarget)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001387 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001388 ERR("Failed to retrieve the render target.");
1389 return error(GL_OUT_OF_MEMORY);
1390 }
1391
1392 bool redefined = redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, mType);
1393
1394 if (!isRenderableFormat())
1395 {
1396 copyNonRenderable(&mImageArray[level], getFormat(), xoffset, yoffset, x, y, width, height, renderTarget);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001397 }
1398 else
1399 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001400 if (redefined)
1401 {
1402 convertToRenderTarget();
1403 pushTexture(mTexture, true);
1404 }
1405 else
1406 {
1407 needRenderTarget();
1408 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001409
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001410 if (level < levelCount())
1411 {
1412 RECT sourceRect;
1413 sourceRect.left = x;
1414 sourceRect.right = x + width;
1415 sourceRect.top = y;
1416 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001417
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001418 IDirect3DSurface9 *dest;
1419 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001420
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001421 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
1422 dest->Release();
1423 }
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001424 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001425}
1426
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001427// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1428bool Texture2D::isComplete() const
1429{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001430 GLsizei width = mImageArray[0].width;
1431 GLsizei height = mImageArray[0].height;
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001432
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001433 if (width <= 0 || height <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001434 {
1435 return false;
1436 }
1437
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001438 bool mipmapping = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001439
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001440 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001441 {
1442 case GL_NEAREST:
1443 case GL_LINEAR:
1444 mipmapping = false;
1445 break;
1446 case GL_NEAREST_MIPMAP_NEAREST:
1447 case GL_LINEAR_MIPMAP_NEAREST:
1448 case GL_NEAREST_MIPMAP_LINEAR:
1449 case GL_LINEAR_MIPMAP_LINEAR:
1450 mipmapping = true;
1451 break;
1452 default: UNREACHABLE();
1453 }
1454
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001455 if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1456 (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1457 {
1458 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1459 {
1460 return false;
1461 }
1462 }
1463
1464
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001465 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1466 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1467 {
1468 return false;
1469 }
1470
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001471 if (mipmapping)
1472 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001473 if (!isPow2(width) || !isPow2(height))
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001474 {
1475 return false;
1476 }
1477
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001478 int q = log2(std::max(width, height));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001479
1480 for (int level = 1; level <= q; level++)
1481 {
1482 if (mImageArray[level].format != mImageArray[0].format)
1483 {
1484 return false;
1485 }
1486
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001487 if (mImageArray[level].width != std::max(1, width >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001488 {
1489 return false;
1490 }
1491
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001492 if (mImageArray[level].height != std::max(1, height >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001493 {
1494 return false;
1495 }
1496 }
1497 }
1498
1499 return true;
1500}
1501
daniel@transgaming.com01868132010-08-24 19:21:17 +00001502bool Texture2D::isCompressed() const
1503{
1504 return IsCompressed(getFormat());
1505}
1506
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001507// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001508IDirect3DBaseTexture9 *Texture2D::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001509{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001510 IDirect3DTexture9 *texture;
1511
1512 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001513 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001514
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001515 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001516
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001517 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001518 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001519 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001520 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001521 }
1522
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001523 if (mTexture) mTexture->Release();
1524 mTexture = texture;
1525 return texture;
1526}
1527
1528void Texture2D::updateTexture()
1529{
1530 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001531
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001532 int levels = levelCount();
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001533
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001534 for (int level = 0; level < levels; level++)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001535 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001536 if (mImageArray[level].dirty)
1537 {
1538 IDirect3DSurface9 *levelSurface = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001539 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001540
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001541 ASSERT(SUCCEEDED(result));
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001542
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001543 if (SUCCEEDED(result))
1544 {
1545 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1546 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001547
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001548 levelSurface->Release();
1549
1550 mImageArray[level].dirty = false;
1551 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001552 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001553 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001554}
1555
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001556IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001557{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001558 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001559
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001560 if (mWidth != 0 && mHeight != 0)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001561 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001562 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001563 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001564 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001565
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001566 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 +00001567
1568 if (FAILED(result))
1569 {
1570 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1571 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1572 }
1573
1574 if (mTexture != NULL)
1575 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001576 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001577 for (int i = 0; i < levels; i++)
1578 {
1579 IDirect3DSurface9 *source;
1580 result = mTexture->GetSurfaceLevel(i, &source);
1581
1582 if (FAILED(result))
1583 {
1584 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1585
1586 texture->Release();
1587
1588 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1589 }
1590
1591 IDirect3DSurface9 *dest;
1592 result = texture->GetSurfaceLevel(i, &dest);
1593
1594 if (FAILED(result))
1595 {
1596 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1597
1598 texture->Release();
1599 source->Release();
1600
1601 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1602 }
1603
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001604 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001605 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1606
1607 if (FAILED(result))
1608 {
1609 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1610
1611 texture->Release();
1612 source->Release();
1613 dest->Release();
1614
1615 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1616 }
1617
1618 source->Release();
1619 dest->Release();
1620 }
1621 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001622 }
1623
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001624 if (mTexture != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001625 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001626 mTexture->Release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001627 }
1628
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001629 mTexture = texture;
1630 return mTexture;
1631}
1632
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001633bool Texture2D::dirtyImageData() const
1634{
1635 int q = log2(std::max(mWidth, mHeight));
1636
1637 for (int i = 0; i <= q; i++)
1638 {
1639 if (mImageArray[i].dirty) return true;
1640 }
1641
1642 return false;
1643}
1644
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001645void Texture2D::generateMipmaps()
1646{
1647 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1648 {
1649 return error(GL_INVALID_OPERATION);
1650 }
1651
1652 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1653 unsigned int q = log2(std::max(mWidth, mHeight));
1654 for (unsigned int i = 1; i <= q; i++)
1655 {
1656 if (mImageArray[i].surface != NULL)
1657 {
1658 mImageArray[i].surface->Release();
1659 mImageArray[i].surface = NULL;
1660 }
1661
1662 mImageArray[i].dirty = false;
1663
1664 mImageArray[i].format = mImageArray[0].format;
1665 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1666 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
1667 }
1668
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00001669 if (isRenderable())
apatrick@chromium.org9398a6b2010-09-20 19:07:49 +00001670 {
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00001671 if (mTexture == NULL)
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001672 {
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00001673 ERR(" failed because mTexture was null.");
1674 return;
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001675 }
1676
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00001677 for (unsigned int i = 1; i <= q; i++)
1678 {
1679 IDirect3DSurface9 *upper = NULL;
1680 IDirect3DSurface9 *lower = NULL;
1681
1682 mTexture->GetSurfaceLevel(i-1, &upper);
1683 mTexture->GetSurfaceLevel(i, &lower);
1684
1685 if (upper != NULL && lower != NULL)
1686 {
1687 getBlitter()->boxFilter(upper, lower);
1688 }
1689
1690 if (upper != NULL) upper->Release();
1691 if (lower != NULL) lower->Release();
1692 }
1693 }
1694 else
1695 {
1696 for (unsigned int i = 1; i <= q; i++)
1697 {
1698 createSurface(mImageArray[i].width, mImageArray[i].height, mImageArray[i].format, mType, &mImageArray[i]);
1699 if (mImageArray[i].surface == NULL)
1700 {
1701 return error(GL_OUT_OF_MEMORY);
1702 }
1703
1704 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1705 {
1706 ERR(" failed to load filter %d to %d.", i - 1, i);
1707 }
1708
1709 mImageArray[i].dirty = true;
1710 }
1711
1712 mDirtyMetaData = true;
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001713 }
1714}
1715
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001716Renderbuffer *Texture2D::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001717{
1718 if (target != GL_TEXTURE_2D)
1719 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001720 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001721 }
1722
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001723 if (mColorbufferProxy.get() == NULL)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001724 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001725 mColorbufferProxy.set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001726 }
1727
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001728 return mColorbufferProxy.get();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001729}
1730
1731IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1732{
1733 ASSERT(target == GL_TEXTURE_2D);
1734
1735 needRenderTarget();
1736
apatrick@chromium.org4d5962c2010-09-20 19:02:30 +00001737 if (mTexture == NULL)
1738 {
1739 return NULL;
1740 }
1741
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001742 IDirect3DSurface9 *renderTarget = NULL;
1743 mTexture->GetSurfaceLevel(0, &renderTarget);
1744
1745 return renderTarget;
1746}
1747
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001748TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001749{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001750 mTexture = NULL;
1751}
1752
1753TextureCubeMap::~TextureCubeMap()
1754{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001755 for (int i = 0; i < 6; i++)
1756 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001757 mFaceProxies[i].set(NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001758 }
1759
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001760 if (mTexture)
1761 {
1762 mTexture->Release();
1763 mTexture = NULL;
1764 }
1765}
1766
1767GLenum TextureCubeMap::getTarget() const
1768{
1769 return GL_TEXTURE_CUBE_MAP;
1770}
1771
daniel@transgaming.com01868132010-08-24 19:21:17 +00001772GLenum TextureCubeMap::getFormat() const
1773{
1774 return mImageArray[0][0].format;
1775}
1776
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001777void 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 +00001778{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001779 setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001780}
1781
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001782void 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 +00001783{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001784 setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001785}
1786
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001787void 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 +00001788{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001789 setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001790}
1791
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001792void 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 +00001793{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001794 setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001795}
1796
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001797void 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 +00001798{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001799 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001800}
1801
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001802void 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 +00001803{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001804 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001805}
1806
daniel@transgaming.com01868132010-08-24 19:21:17 +00001807void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1808{
1809 redefineTexture(level, internalFormat, width);
1810
1811 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[faceIndex(face)][level]);
1812}
1813
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001814void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1815{
1816 int face = faceIndex(faceTarget);
1817
1818 ASSERT(mImageArray[face][level].surface != NULL);
1819
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001820 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001821 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001822 IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level);
1823 ASSERT(destLevel != NULL);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001824
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001825 if (destLevel != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001826 {
1827 Image *img = &mImageArray[face][level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001828
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001829 RECT sourceRect;
1830 sourceRect.left = xoffset;
1831 sourceRect.top = yoffset;
1832 sourceRect.right = xoffset + width;
1833 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001834
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001835 POINT destPoint;
1836 destPoint.x = xoffset;
1837 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001838
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001839 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001840 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001841
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001842 destLevel->Release();
1843
1844 img->dirty = false;
1845 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001846 }
1847}
1848
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001849void TextureCubeMap::subImage(GLenum target, 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 +00001850{
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001851 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
daniel@transgaming.com31273552010-08-04 13:42:44 +00001852 {
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001853 commitRect(target, level, xoffset, yoffset, width, height);
daniel@transgaming.com31273552010-08-04 13:42:44 +00001854 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001855}
1856
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001857void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
daniel@transgaming.com01868132010-08-24 19:21:17 +00001858{
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001859 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
daniel@transgaming.com01868132010-08-24 19:21:17 +00001860 {
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001861 commitRect(target, level, xoffset, yoffset, width, height);
daniel@transgaming.com01868132010-08-24 19:21:17 +00001862 }
1863}
1864
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001865// 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 +00001866bool TextureCubeMap::isComplete() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001867{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001868 int size = mImageArray[0][0].width;
1869
1870 if (size <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001871 {
1872 return false;
1873 }
1874
1875 bool mipmapping;
1876
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001877 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001878 {
1879 case GL_NEAREST:
1880 case GL_LINEAR:
1881 mipmapping = false;
1882 break;
1883 case GL_NEAREST_MIPMAP_NEAREST:
1884 case GL_LINEAR_MIPMAP_NEAREST:
1885 case GL_NEAREST_MIPMAP_LINEAR:
1886 case GL_LINEAR_MIPMAP_LINEAR:
1887 mipmapping = true;
1888 break;
1889 default: UNREACHABLE();
1890 }
1891
1892 for (int face = 0; face < 6; face++)
1893 {
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001894 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001895 {
1896 return false;
1897 }
1898 }
1899
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001900 if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1901 (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1902 {
1903 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1904 {
1905 return false;
1906 }
1907 }
1908
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001909 if (mipmapping)
1910 {
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001911 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1912 {
1913 return false;
1914 }
1915
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001916 int q = log2(size);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001917
1918 for (int face = 0; face < 6; face++)
1919 {
1920 for (int level = 1; level <= q; level++)
1921 {
1922 if (mImageArray[face][level].format != mImageArray[0][0].format)
1923 {
1924 return false;
1925 }
1926
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001927 if (mImageArray[face][level].width != std::max(1, size >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001928 {
1929 return false;
1930 }
1931
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001932 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001933 }
1934 }
1935 }
1936
1937 return true;
1938}
1939
daniel@transgaming.com01868132010-08-24 19:21:17 +00001940bool TextureCubeMap::isCompressed() const
1941{
1942 return IsCompressed(getFormat());
1943}
1944
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001945// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001946IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001947{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001948 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001949 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001950
1951 IDirect3DCubeTexture9 *texture;
1952
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001953 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001954
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001955 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001956 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001957 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001958 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001959 }
1960
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001961 if (mTexture) mTexture->Release();
1962
1963 mTexture = texture;
1964 return mTexture;
1965}
1966
1967void TextureCubeMap::updateTexture()
1968{
1969 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001970
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001971 for (int face = 0; face < 6; face++)
1972 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001973 int levels = levelCount();
1974 for (int level = 0; level < levels; level++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001975 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001976 Image *img = &mImageArray[face][level];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001977
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001978 if (img->dirty)
1979 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001980 IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level);
1981 ASSERT(levelSurface != NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001982
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001983 if (levelSurface != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001984 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001985 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001986 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001987
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001988 levelSurface->Release();
1989
1990 img->dirty = false;
1991 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001992 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001993 }
1994 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001995}
1996
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001997IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
1998{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001999 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00002000
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002001 if (mWidth != 0)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00002002 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00002003 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002004 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00002005 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002006
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00002007 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002008
2009 if (FAILED(result))
2010 {
2011 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2012 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
2013 }
2014
2015 if (mTexture != NULL)
2016 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00002017 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002018 for (int f = 0; f < 6; f++)
2019 {
2020 for (int i = 0; i < levels; i++)
2021 {
2022 IDirect3DSurface9 *source;
2023 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2024
2025 if (FAILED(result))
2026 {
2027 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2028
2029 texture->Release();
2030
2031 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
2032 }
2033
2034 IDirect3DSurface9 *dest;
2035 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2036
2037 if (FAILED(result))
2038 {
2039 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2040
2041 texture->Release();
2042 source->Release();
2043
2044 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
2045 }
2046
daniel@transgaming.comae072af2010-05-05 18:47:28 +00002047 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002048 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2049
2050 if (FAILED(result))
2051 {
2052 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2053
2054 texture->Release();
2055 source->Release();
2056 dest->Release();
2057
2058 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
2059 }
2060 }
2061 }
2062 }
daniel@transgaming.com7051b972010-03-21 04:31:07 +00002063 }
2064
2065 if (mTexture != NULL)
2066 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00002067 mTexture->Release();
2068 }
2069
2070 mTexture = texture;
2071 return mTexture;
2072}
2073
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00002074void 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 +00002075{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002076 redefineTexture(level, internalFormat, width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002077
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002078 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002079}
daniel@transgaming.com00c75962010-03-11 20:36:15 +00002080
2081unsigned int TextureCubeMap::faceIndex(GLenum face)
2082{
2083 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2084 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2085 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2086 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2087 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2088
2089 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2090}
2091
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00002092bool TextureCubeMap::dirtyImageData() const
2093{
2094 int q = log2(mWidth);
2095
2096 for (int f = 0; f < 6; f++)
2097 {
2098 for (int i = 0; i <= q; i++)
2099 {
2100 if (mImageArray[f][i].dirty) return true;
2101 }
2102 }
2103
2104 return false;
2105}
2106
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002107// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
2108// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
2109// Call this when a particular level of the texture must be defined with a specific format, width and height.
2110//
2111// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
2112// a new size for the texture by working backwards from the given size.
2113bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
2114{
2115 // Are these settings compatible with level 0?
2116 bool sizeOkay = (mImageArray[0][0].width >> level == width);
2117
2118 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
2119
2120 if (!textureOkay)
2121 {
2122 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
2123 mImageArray[0][0].format, mImageArray[0][0].width,
2124 internalFormat, width);
2125
2126 // Purge all the levels and the texture.
daniel@transgaming.com5d752f22010-10-07 13:37:20 +00002127 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002128 {
2129 for (int f = 0; f < 6; f++)
2130 {
2131 if (mImageArray[f][i].surface != NULL)
2132 {
2133 mImageArray[f][i].dirty = false;
2134
2135 mImageArray[f][i].surface->Release();
2136 mImageArray[f][i].surface = NULL;
2137 }
2138 }
2139 }
2140
2141 if (mTexture != NULL)
2142 {
2143 mTexture->Release();
2144 mTexture = NULL;
2145 dropTexture();
2146 }
2147
2148 mWidth = width << level;
2149 mImageArray[0][0].width = width << level;
2150 mHeight = width << level;
2151 mImageArray[0][0].height = width << level;
2152
2153 mImageArray[0][0].format = internalFormat;
2154 }
2155
2156 return !textureOkay;
2157}
2158
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00002159void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002160{
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002161 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002162
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002163 if (!renderTarget)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002164 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002165 ERR("Failed to retrieve the render target.");
2166 return error(GL_OUT_OF_MEMORY);
2167 }
2168
2169 unsigned int faceindex = faceIndex(target);
2170 bool redefined = redefineTexture(level, internalFormat, width);
2171
2172 if (!isRenderableFormat())
2173 {
2174 copyNonRenderable(&mImageArray[faceindex][level], internalFormat, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002175 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00002176 else
2177 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002178 if (redefined)
2179 {
2180 convertToRenderTarget();
2181 pushTexture(mTexture, true);
2182 }
2183 else
2184 {
2185 needRenderTarget();
2186 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002187
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002188 ASSERT(width == height);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002189
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002190 if (width > 0 && level < levelCount())
2191 {
2192 RECT sourceRect;
2193 sourceRect.left = x;
2194 sourceRect.right = x + width;
2195 sourceRect.top = y;
2196 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002197
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002198 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002199
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002200 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
2201 dest->Release();
2202 }
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002203 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002204
2205 mImageArray[faceindex][level].width = width;
2206 mImageArray[faceindex][level].height = height;
2207 mImageArray[faceindex][level].format = internalFormat;
2208}
2209
2210IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(unsigned int faceIdentifier, unsigned int level)
2211{
2212 unsigned int faceIndex;
2213
2214 if (faceIdentifier < 6)
2215 {
2216 faceIndex = faceIdentifier;
2217 }
2218 else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
2219 {
2220 faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2221 }
2222 else
2223 {
2224 UNREACHABLE();
2225 faceIndex = 0;
2226 }
2227
2228 if (mTexture == NULL)
2229 {
2230 UNREACHABLE();
2231 return NULL;
2232 }
2233
2234 IDirect3DSurface9 *surface = NULL;
2235
2236 HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface);
2237
2238 return (SUCCEEDED(hr)) ? surface : NULL;
2239}
2240
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00002241void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002242{
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00002243 GLsizei size = mImageArray[faceIndex(target)][level].width;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002244
2245 if (xoffset + width > size || yoffset + height > size)
2246 {
2247 return error(GL_INVALID_VALUE);
2248 }
2249
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002250 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2251
2252 if (!renderTarget)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002253 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002254 ERR("Failed to retrieve the render target.");
2255 return error(GL_OUT_OF_MEMORY);
2256 }
2257
2258 unsigned int faceindex = faceIndex(target);
2259 bool redefined = redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width);
2260
2261 if (!isRenderableFormat())
2262 {
2263 copyNonRenderable(&mImageArray[faceindex][level], getFormat(), 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002264 }
2265 else
2266 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002267 if (redefined)
2268 {
2269 convertToRenderTarget();
2270 pushTexture(mTexture, true);
2271 }
2272 else
2273 {
2274 needRenderTarget();
2275 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002276
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002277 if (level < levelCount())
2278 {
2279 RECT sourceRect;
2280 sourceRect.left = x;
2281 sourceRect.right = x + width;
2282 sourceRect.top = y;
2283 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002284
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002285 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002286
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002287 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
2288 dest->Release();
2289 }
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00002290 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002291}
2292
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00002293bool TextureCubeMap::isCubeComplete() const
2294{
2295 if (mImageArray[0][0].width == 0)
2296 {
2297 return false;
2298 }
2299
2300 for (unsigned int f = 1; f < 6; f++)
2301 {
2302 if (mImageArray[f][0].width != mImageArray[0][0].width
2303 || mImageArray[f][0].format != mImageArray[0][0].format)
2304 {
2305 return false;
2306 }
2307 }
2308
2309 return true;
2310}
2311
2312void TextureCubeMap::generateMipmaps()
2313{
2314 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
2315 {
2316 return error(GL_INVALID_OPERATION);
2317 }
2318
2319 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2320 unsigned int q = log2(mImageArray[0][0].width);
2321 for (unsigned int f = 0; f < 6; f++)
2322 {
2323 for (unsigned int i = 1; i <= q; i++)
2324 {
2325 if (mImageArray[f][i].surface != NULL)
2326 {
2327 mImageArray[f][i].surface->Release();
2328 mImageArray[f][i].surface = NULL;
2329 }
2330
2331 mImageArray[f][i].dirty = false;
2332
2333 mImageArray[f][i].format = mImageArray[f][0].format;
2334 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2335 mImageArray[f][i].height = mImageArray[f][i].width;
2336 }
2337 }
2338
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00002339 if (isRenderable())
apatrick@chromium.org9398a6b2010-09-20 19:07:49 +00002340 {
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00002341 if (mTexture == NULL)
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00002342 {
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00002343 return;
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00002344 }
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00002345
2346 for (unsigned int f = 0; f < 6; f++)
2347 {
2348 for (unsigned int i = 1; i <= q; i++)
2349 {
2350 IDirect3DSurface9 *upper = getCubeMapSurface(f, i-1);
2351 IDirect3DSurface9 *lower = getCubeMapSurface(f, i);
2352
2353 if (upper != NULL && lower != NULL)
2354 {
2355 getBlitter()->boxFilter(upper, lower);
2356 }
2357
2358 if (upper != NULL) upper->Release();
2359 if (lower != NULL) lower->Release();
2360 }
2361 }
2362 }
2363 else
2364 {
2365 for (unsigned int f = 0; f < 6; f++)
2366 {
2367 for (unsigned int i = 1; i <= q; i++)
2368 {
2369 createSurface(mImageArray[f][i].width, mImageArray[f][i].height, mImageArray[f][i].format, mType, &mImageArray[f][i]);
2370 if (mImageArray[f][i].surface == NULL)
2371 {
2372 return error(GL_OUT_OF_MEMORY);
2373 }
2374
2375 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2376 {
2377 ERR(" failed to load filter %d to %d.", i - 1, i);
2378 }
2379
2380 mImageArray[f][i].dirty = true;
2381 }
2382 }
2383
2384 mDirtyMetaData = true;
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00002385 }
2386}
2387
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002388Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002389{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002390 if (!IsCubemapTextureTarget(target))
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002391 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002392 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002393 }
2394
2395 unsigned int face = faceIndex(target);
2396
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002397 if (mFaceProxies[face].get() == NULL)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002398 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002399 mFaceProxies[face].set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002400 }
2401
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002402 return mFaceProxies[face].get();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002403}
2404
2405IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2406{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002407 ASSERT(IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002408
2409 needRenderTarget();
daniel@transgaming.come979ead2010-09-23 18:03:14 +00002410
2411 if (mTexture == NULL)
2412 {
2413 return NULL;
apatrick@chromium.org4d5962c2010-09-20 19:02:30 +00002414 }
2415
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002416 IDirect3DSurface9 *renderTarget = NULL;
2417 mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex(target)), 0, &renderTarget);
2418
2419 return renderTarget;
2420}
2421
2422Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
enne@chromium.org0fa74632010-09-21 16:18:52 +00002423 : Colorbuffer(texture), mTexture(texture), mTarget(target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002424{
daniel@transgaming.comedc19182010-10-15 17:57:55 +00002425 ASSERT(IsTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002426}
2427
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002428void Texture::TextureColorbufferProxy::addRef() const
2429{
2430 mTexture->addRef();
2431}
2432
2433void Texture::TextureColorbufferProxy::release() const
2434{
2435 mTexture->release();
2436}
2437
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002438IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
2439{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002440 if (mRenderTarget) mRenderTarget->Release();
2441
2442 mRenderTarget = mTexture->getRenderTarget(mTarget);
2443
2444 return mRenderTarget;
2445}
2446
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002447int Texture::TextureColorbufferProxy::getWidth() const
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002448{
daniel@transgaming.com866f3182010-05-20 19:28:22 +00002449 return mTexture->getWidth();
2450}
2451
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002452int Texture::TextureColorbufferProxy::getHeight() const
daniel@transgaming.com866f3182010-05-20 19:28:22 +00002453{
2454 return mTexture->getHeight();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002455}
2456
daniel@transgaming.com01868132010-08-24 19:21:17 +00002457GLenum Texture::TextureColorbufferProxy::getFormat() const
2458{
2459 return mTexture->getFormat();
2460}
2461
daniel@transgaming.com1297d922010-09-01 15:47:47 +00002462bool Texture::TextureColorbufferProxy::isFloatingPoint() const
2463{
2464 return mTexture->isFloatingPoint();
2465}
2466
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002467}