blob: b7dc370f4ea752d5e679f3f648a4e4a4c06a713b [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{
415 const unsigned char *source = NULL;
416 unsigned char *dest = NULL;
417
418 for (int y = 0; y < height; y++)
419 {
420 source = static_cast<const unsigned char*>(input) + y * inputPitch;
421 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000422
423 if (!native) // BGRA8 destination format
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000424 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000425 for (int x = 0; x < width; x++)
426 {
427 dest[4 * x + 0] = source[x];
428 dest[4 * x + 1] = source[x];
429 dest[4 * x + 2] = source[x];
430 dest[4 * x + 3] = 0xFF;
431 }
432 }
433 else // L8 destination format
434 {
435 memcpy(dest, source, width);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000436 }
437 }
438}
439
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000440void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
441 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
442{
443 const float *source = NULL;
444 float *dest = NULL;
445
446 for (int y = 0; y < height; y++)
447 {
448 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
449 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
450 for (int x = 0; x < width; x++)
451 {
452 dest[4 * x + 0] = source[x];
453 dest[4 * x + 1] = source[x];
454 dest[4 * x + 2] = source[x];
455 dest[4 * x + 3] = 1.0f;
456 }
457 }
458}
459
460void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
461 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
462{
463 const unsigned short *source = NULL;
464 unsigned short *dest = NULL;
465
466 for (int y = 0; y < height; y++)
467 {
468 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
469 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
470 for (int x = 0; x < width; x++)
471 {
472 dest[4 * x + 0] = source[x];
473 dest[4 * x + 1] = source[x];
474 dest[4 * x + 2] = source[x];
475 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
476 }
477 }
478}
479
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000480void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000481 size_t inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000482{
483 const unsigned char *source = NULL;
484 unsigned char *dest = NULL;
485
486 for (int y = 0; y < height; y++)
487 {
488 source = static_cast<const unsigned char*>(input) + y * inputPitch;
489 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000490
491 if (!native) // BGRA8 destination format
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000492 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000493 for (int x = 0; x < width; x++)
494 {
495 dest[4 * x + 0] = source[2*x+0];
496 dest[4 * x + 1] = source[2*x+0];
497 dest[4 * x + 2] = source[2*x+0];
498 dest[4 * x + 3] = source[2*x+1];
499 }
500 }
501 else
502 {
503 memcpy(dest, source, width * 2);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000504 }
505 }
506}
507
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000508void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
509 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
510{
511 const float *source = NULL;
512 float *dest = NULL;
513
514 for (int y = 0; y < height; y++)
515 {
516 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
517 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
518 for (int x = 0; x < width; x++)
519 {
520 dest[4 * x + 0] = source[2*x+0];
521 dest[4 * x + 1] = source[2*x+0];
522 dest[4 * x + 2] = source[2*x+0];
523 dest[4 * x + 3] = source[2*x+1];
524 }
525 }
526}
527
528void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
529 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
530{
531 const unsigned short *source = NULL;
532 unsigned short *dest = NULL;
533
534 for (int y = 0; y < height; y++)
535 {
536 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
537 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
538 for (int x = 0; x < width; x++)
539 {
540 dest[4 * x + 0] = source[2*x+0];
541 dest[4 * x + 1] = source[2*x+0];
542 dest[4 * x + 2] = source[2*x+0];
543 dest[4 * x + 3] = source[2*x+1];
544 }
545 }
546}
547
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000548void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
549 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
550{
551 const unsigned char *source = NULL;
552 unsigned char *dest = NULL;
553
554 for (int y = 0; y < height; y++)
555 {
556 source = static_cast<const unsigned char*>(input) + y * inputPitch;
557 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
558 for (int x = 0; x < width; x++)
559 {
560 dest[4 * x + 0] = source[x * 3 + 2];
561 dest[4 * x + 1] = source[x * 3 + 1];
562 dest[4 * x + 2] = source[x * 3 + 0];
563 dest[4 * x + 3] = 0xFF;
564 }
565 }
566}
567
568void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
569 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
570{
571 const unsigned short *source = NULL;
572 unsigned char *dest = NULL;
573
574 for (int y = 0; y < height; y++)
575 {
576 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
577 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
578 for (int x = 0; x < width; x++)
579 {
580 unsigned short rgba = source[x];
581 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
582 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
583 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
584 dest[4 * x + 3] = 0xFF;
585 }
586 }
587}
588
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000589void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
590 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
591{
592 const float *source = NULL;
593 float *dest = NULL;
594
595 for (int y = 0; y < height; y++)
596 {
597 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
598 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
599 for (int x = 0; x < width; x++)
600 {
601 dest[4 * x + 0] = source[x * 3 + 0];
602 dest[4 * x + 1] = source[x * 3 + 1];
603 dest[4 * x + 2] = source[x * 3 + 2];
604 dest[4 * x + 3] = 1.0f;
605 }
606 }
607}
608
609void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
610 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
611{
612 const unsigned short *source = NULL;
613 unsigned short *dest = NULL;
614
615 for (int y = 0; y < height; y++)
616 {
617 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
618 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
619 for (int x = 0; x < width; x++)
620 {
621 dest[4 * x + 0] = source[x * 3 + 0];
622 dest[4 * x + 1] = source[x * 3 + 1];
623 dest[4 * x + 2] = source[x * 3 + 2];
624 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
625 }
626 }
627}
628
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000629void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
630 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
631{
632 const unsigned char *source = NULL;
633 unsigned char *dest = NULL;
634
635 for (int y = 0; y < height; y++)
636 {
637 source = static_cast<const unsigned char*>(input) + y * inputPitch;
638 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
639 for (int x = 0; x < width; x++)
640 {
641 dest[4 * x + 0] = source[x * 4 + 2];
642 dest[4 * x + 1] = source[x * 4 + 1];
643 dest[4 * x + 2] = source[x * 4 + 0];
644 dest[4 * x + 3] = source[x * 4 + 3];
645 }
646 }
647}
648
649void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
650 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
651{
652 const unsigned short *source = NULL;
653 unsigned char *dest = NULL;
654
655 for (int y = 0; y < height; y++)
656 {
657 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
658 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
659 for (int x = 0; x < width; x++)
660 {
661 unsigned short rgba = source[x];
662 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
663 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
664 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
665 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
666 }
667 }
668}
669
670void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
671 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
672{
673 const unsigned short *source = NULL;
674 unsigned char *dest = NULL;
675
676 for (int y = 0; y < height; y++)
677 {
678 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
679 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
680 for (int x = 0; x < width; x++)
681 {
682 unsigned short rgba = source[x];
683 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
684 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
685 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
686 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
687 }
688 }
689}
690
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000691void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
692 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
693{
694 const float *source = NULL;
695 float *dest = NULL;
696
697 for (int y = 0; y < height; y++)
698 {
699 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
700 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
701 memcpy(dest, source, width * 16);
702 }
703}
704
705void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
706 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
707{
708 const unsigned char *source = NULL;
709 unsigned char *dest = NULL;
710
711 for (int y = 0; y < height; y++)
712 {
713 source = static_cast<const unsigned char*>(input) + y * inputPitch;
714 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
715 memcpy(dest, source, width * 8);
716 }
717}
718
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000719void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
720 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
721{
722 const unsigned char *source = NULL;
723 unsigned char *dest = NULL;
724
725 for (int y = 0; y < height; y++)
726 {
727 source = static_cast<const unsigned char*>(input) + y * inputPitch;
728 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
729 memcpy(dest, source, width*4);
730 }
731}
732
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000733void Texture::createSurface(GLsizei width, GLsizei height, GLenum format, GLenum type, Image *img)
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000734{
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000735 IDirect3DTexture9 *newTexture = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000736 IDirect3DSurface9 *newSurface = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000737
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000738 if (width != 0 && height != 0)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000739 {
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000740 int levelToFetch = 0;
741 GLsizei requestWidth = width;
742 GLsizei requestHeight = height;
743 if (IsCompressed(format) && (width % 4 != 0 || height % 4 != 0))
744 {
745 bool isMult4 = false;
746 int upsampleCount = 0;
747 while (!isMult4)
748 {
749 requestWidth <<= 1;
750 requestHeight <<= 1;
751 upsampleCount++;
752 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
753 {
754 isMult4 = true;
755 }
756 }
757 levelToFetch = upsampleCount;
758 }
759
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000760 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, selectFormat(format, type),
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000761 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000762
763 if (FAILED(result))
764 {
765 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
766 return error(GL_OUT_OF_MEMORY);
767 }
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000768
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000769 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000770 newTexture->Release();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000771 }
772
773 if (img->surface) img->surface->Release();
774 img->surface = newSurface;
775
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000776 img->width = width;
777 img->height = height;
778 img->format = format;
daniel@transgaming.com01868132010-08-24 19:21:17 +0000779}
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000780
daniel@transgaming.com01868132010-08-24 19:21:17 +0000781void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
782{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000783 createSurface(width, height, format, type, img);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000784
785 if (pixels != NULL && img->surface != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000786 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000787 D3DSURFACE_DESC description;
788 img->surface->GetDesc(&description);
789
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000790 D3DLOCKED_RECT locked;
daniel@transgaming.com01868132010-08-24 19:21:17 +0000791 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000792
793 ASSERT(SUCCEEDED(result));
794
795 if (SUCCEEDED(result))
796 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000797 loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000798 img->surface->UnlockRect();
799 }
800
801 img->dirty = true;
802 }
803
804 mDirtyMetaData = true;
805}
806
807void Texture::setCompressedImage(GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
808{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000809 createSurface(width, height, format, GL_UNSIGNED_BYTE, img);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000810
811 if (pixels != NULL && img->surface != NULL)
812 {
813 D3DLOCKED_RECT locked;
814 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
815
816 ASSERT(SUCCEEDED(result));
817
818 if (SUCCEEDED(result))
819 {
820 memcpy(locked.pBits, pixels, imageSize);
821 img->surface->UnlockRect();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000822 }
823
824 img->dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000825 }
826
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000827 mDirtyMetaData = true;
828}
829
daniel@transgaming.com31273552010-08-04 13:42:44 +0000830bool 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 +0000831{
daniel@transgaming.com31273552010-08-04 13:42:44 +0000832 if (width + xoffset > img->width || height + yoffset > img->height)
833 {
834 error(GL_INVALID_VALUE);
835 return false;
836 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000837
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000838 if (!img->surface)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000839 {
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000840 createSurface(img->width, img->height, format, type, img);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000841 }
842
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000843 if (pixels != NULL && img->surface != NULL)
844 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000845 D3DSURFACE_DESC description;
846 img->surface->GetDesc(&description);
847
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000848 D3DLOCKED_RECT locked;
849 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
850
851 ASSERT(SUCCEEDED(result));
852
853 if (SUCCEEDED(result))
854 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000855 loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000856 img->surface->UnlockRect();
857 }
858
859 img->dirty = true;
860 }
861
daniel@transgaming.com31273552010-08-04 13:42:44 +0000862 return true;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000863}
864
daniel@transgaming.com01868132010-08-24 19:21:17 +0000865bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
866{
867 if (width + xoffset > img->width || height + yoffset > img->height)
868 {
869 error(GL_INVALID_VALUE);
870 return false;
871 }
872
873 if (format != getFormat())
874 {
875 error(GL_INVALID_OPERATION);
876 return false;
877 }
878
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000879 if (!img->surface)
daniel@transgaming.com01868132010-08-24 19:21:17 +0000880 {
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000881 createSurface(img->width, img->height, format, GL_UNSIGNED_BYTE, img);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000882 }
883
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000884 if (pixels != NULL && img->surface != NULL)
885 {
886 RECT updateRegion;
887 updateRegion.left = xoffset;
888 updateRegion.right = xoffset + width;
889 updateRegion.bottom = yoffset + height;
890 updateRegion.top = yoffset;
891
892 D3DLOCKED_RECT locked;
893 HRESULT result = img->surface->LockRect(&locked, &updateRegion, 0);
894
895 ASSERT(SUCCEEDED(result));
896
897 if (SUCCEEDED(result))
898 {
899 GLsizei inputPitch = ComputeCompressedPitch(width, format);
900 int rows = imageSize / inputPitch;
901 for (int i = 0; i < rows; ++i)
902 {
903 memcpy((void*)((BYTE*)locked.pBits + i * locked.Pitch), (void*)((BYTE*)pixels + i * inputPitch), inputPitch);
904 }
905 img->surface->UnlockRect();
906 }
907
908 img->dirty = true;
909 }
910
daniel@transgaming.com01868132010-08-24 19:21:17 +0000911 return true;
912}
913
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +0000914// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats
915void Texture::copyNonRenderable(Image *image, GLenum internalFormat, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
916{
917 IDirect3DDevice9 *device = getDevice();
918 IDirect3DSurface9 *surface = NULL;
919 D3DSURFACE_DESC description;
920 renderTarget->GetDesc(&description);
921
922 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
923
924 if (!SUCCEEDED(result))
925 {
926 ERR("Could not create matching destination surface.");
927 return error(GL_OUT_OF_MEMORY);
928 }
929
930 result = device->GetRenderTargetData(renderTarget, surface);
931
932 if (!SUCCEEDED(result))
933 {
934 ERR("GetRenderTargetData unexpectedly failed.");
935 surface->Release();
936 return error(GL_OUT_OF_MEMORY);
937 }
938
939 D3DLOCKED_RECT sourceLock = {0};
940 RECT sourceRect = {x, y, x + width, y + height};
941 result = surface->LockRect(&sourceLock, &sourceRect, 0);
942
943 if (FAILED(result))
944 {
945 ERR("Failed to lock the source surface (rectangle might be invalid).");
946 surface->UnlockRect();
947 surface->Release();
948 return error(GL_OUT_OF_MEMORY);
949 }
950
951 if (!image->surface)
952 {
953 createSurface(width, height, internalFormat, mType, image);
954 }
955
956 if (image->surface == NULL)
957 {
958 ERR("Failed to create an image surface.");
959 surface->UnlockRect();
960 surface->Release();
961 return error(GL_OUT_OF_MEMORY);
962 }
963
964 D3DLOCKED_RECT destLock = {0};
965 RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height};
966 result = image->surface->LockRect(&destLock, &destRect, 0);
967
968 if (FAILED(result))
969 {
970 ERR("Failed to lock the destination surface (rectangle might be invalid).");
971 surface->UnlockRect();
972 surface->Release();
973 return error(GL_OUT_OF_MEMORY);
974 }
975
976 if (destLock.pBits && sourceLock.pBits)
977 {
978 unsigned char *source = (unsigned char*)sourceLock.pBits;
979 unsigned char *dest = (unsigned char*)destLock.pBits;
980
981 switch (description.Format)
982 {
983 case D3DFMT_X8R8G8B8:
984 case D3DFMT_A8R8G8B8:
985 switch(getD3DFormat())
986 {
987 case D3DFMT_L8:
988 for(int y = 0; y < height; y++)
989 {
990 for(int x = 0; x < height; x++)
991 {
992 dest[x] = source[x * 4 + 2];
993 }
994
995 source += sourceLock.Pitch;
996 dest += destLock.Pitch;
997 }
998 break;
999 case D3DFMT_A8L8:
1000 for(int y = 0; y < height; y++)
1001 {
1002 for(int x = 0; x < height; x++)
1003 {
1004 dest[x * 2 + 0] = source[x * 4 + 2];
1005 dest[x * 2 + 1] = source[x * 4 + 3];
1006 }
1007
1008 source += sourceLock.Pitch;
1009 dest += destLock.Pitch;
1010 }
1011 break;
1012 default:
1013 UNREACHABLE();
1014 }
1015 break;
daniel@transgaming.comfe5141e2010-10-18 12:18:12 +00001016 case D3DFMT_R5G6B5:
1017 switch(getD3DFormat())
1018 {
1019 case D3DFMT_L8:
1020 for(int y = 0; y < height; y++)
1021 {
1022 for(int x = 0; x < height; x++)
1023 {
1024 unsigned char red = source[x * 2 + 1] & 0xF8;
1025 dest[x] = red | (red >> 5);
1026 }
1027
1028 source += sourceLock.Pitch;
1029 dest += destLock.Pitch;
1030 }
1031 break;
1032 default:
1033 UNREACHABLE();
1034 }
1035 break;
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001036 default:
1037 UNREACHABLE();
1038 }
1039
1040 image->dirty = true;
1041 mDirtyMetaData = true;
1042 }
1043
1044 image->surface->UnlockRect();
1045 surface->UnlockRect();
1046 surface->Release();
1047}
1048
enne@chromium.org0fa74632010-09-21 16:18:52 +00001049D3DFORMAT Texture::getD3DFormat() const
1050{
1051 return selectFormat(getFormat(), mType);
1052}
1053
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001054IDirect3DBaseTexture9 *Texture::getTexture()
1055{
1056 if (!isComplete())
1057 {
1058 return NULL;
1059 }
1060
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001061 if (mDirtyMetaData)
1062 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001063 mBaseTexture = createTexture();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001064 mIsRenderable = false;
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001065 }
1066
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001067 if (mDirtyMetaData || dirtyImageData())
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001068 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001069 updateTexture();
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001070 }
1071
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001072 mDirtyMetaData = false;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001073 ASSERT(!dirtyImageData());
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001074
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001075 return mBaseTexture;
1076}
1077
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00001078bool Texture::isDirty() const
1079{
1080 return (mDirty || mDirtyMetaData || dirtyImageData());
1081}
1082
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001083// Returns the top-level texture surface as a render target
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001084void Texture::needRenderTarget()
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001085{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001086 if (!mIsRenderable)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001087 {
1088 mBaseTexture = convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001089 mIsRenderable = true;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001090 }
1091
1092 if (dirtyImageData())
1093 {
1094 updateTexture();
1095 }
1096
1097 mDirtyMetaData = false;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001098}
1099
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001100void Texture::dropTexture()
1101{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001102 if (mBaseTexture)
1103 {
1104 mBaseTexture = NULL;
1105 }
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001106
1107 mIsRenderable = false;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001108}
1109
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001110void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001111{
1112 mBaseTexture = newTexture;
1113 mDirtyMetaData = false;
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001114 mIsRenderable = renderable;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00001115 mDirty = true;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001116}
1117
1118
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001119GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1120{
1121 if (isPow2(width) && isPow2(height))
1122 {
1123 return maxlevel;
1124 }
1125 else
1126 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001127 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1128 return 1;
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001129 }
1130}
1131
1132GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1133{
1134 return creationLevels(size, size, maxlevel);
1135}
1136
1137int Texture::levelCount() const
1138{
1139 return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
1140}
1141
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00001142bool Texture::isRenderable() const
1143{
1144 return mIsRenderable;
1145}
1146
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001147Texture2D::Texture2D(GLuint id) : Texture(id)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001148{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001149 mTexture = NULL;
1150}
1151
1152Texture2D::~Texture2D()
1153{
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001154 mColorbufferProxy.set(NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001155
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001156 if (mTexture)
1157 {
1158 mTexture->Release();
1159 mTexture = NULL;
1160 }
1161}
1162
1163GLenum Texture2D::getTarget() const
1164{
1165 return GL_TEXTURE_2D;
1166}
1167
daniel@transgaming.com01868132010-08-24 19:21:17 +00001168GLenum Texture2D::getFormat() const
1169{
1170 return mImageArray[0].format;
1171}
1172
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001173// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1174// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
1175// Call this when a particular level of the texture must be defined with a specific format, width and height.
1176//
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +00001177// 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 +00001178// 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 +00001179bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001180{
1181 bool widthOkay = (mWidth >> level == width);
1182 bool heightOkay = (mHeight >> level == height);
1183
1184 bool sizeOkay = ((widthOkay && heightOkay)
1185 || (widthOkay && mHeight >> level == 0 && height == 1)
1186 || (heightOkay && mWidth >> level == 0 && width == 1));
1187
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001188 bool typeOkay = (type == mType);
1189
1190 bool textureOkay = (sizeOkay && typeOkay && internalFormat == mImageArray[0].format);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001191
1192 if (!textureOkay)
1193 {
1194 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
1195 mImageArray[0].format, mWidth, mHeight,
1196 internalFormat, width, height);
1197
1198 // Purge all the levels and the texture.
1199
daniel@transgaming.com5d752f22010-10-07 13:37:20 +00001200 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001201 {
1202 if (mImageArray[i].surface != NULL)
1203 {
1204 mImageArray[i].dirty = false;
1205
1206 mImageArray[i].surface->Release();
1207 mImageArray[i].surface = NULL;
1208 }
1209 }
1210
1211 if (mTexture != NULL)
1212 {
1213 mTexture->Release();
1214 mTexture = NULL;
1215 dropTexture();
1216 }
1217
1218 mWidth = width << level;
1219 mHeight = height << level;
1220 mImageArray[0].format = internalFormat;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001221 mType = type;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001222 }
1223
1224 return !textureOkay;
1225}
1226
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001227void 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 +00001228{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001229 redefineTexture(level, internalFormat, width, height, type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001230
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001231 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001232}
1233
daniel@transgaming.com01868132010-08-24 19:21:17 +00001234void Texture2D::setCompressedImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1235{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001236 redefineTexture(level, internalFormat, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.com01868132010-08-24 19:21:17 +00001237
1238 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[level]);
1239}
1240
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001241void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1242{
1243 ASSERT(mImageArray[level].surface != NULL);
1244
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001245 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001246 {
1247 IDirect3DSurface9 *destLevel = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001248 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001249
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001250 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001251
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001252 if (SUCCEEDED(result))
1253 {
1254 Image *img = &mImageArray[level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001255
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001256 RECT sourceRect;
1257 sourceRect.left = xoffset;
1258 sourceRect.top = yoffset;
1259 sourceRect.right = xoffset + width;
1260 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001261
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001262 POINT destPoint;
1263 destPoint.x = xoffset;
1264 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001265
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001266 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
1267 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001268
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001269 destLevel->Release();
1270
1271 img->dirty = false;
1272 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001273 }
1274}
1275
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001276void 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 +00001277{
daniel@transgaming.com31273552010-08-04 13:42:44 +00001278 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1279 {
1280 commitRect(level, xoffset, yoffset, width, height);
1281 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001282}
1283
daniel@transgaming.com01868132010-08-24 19:21:17 +00001284void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1285{
1286 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1287 {
1288 commitRect(level, xoffset, yoffset, width, height);
1289 }
1290}
1291
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001292void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001293{
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001294 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1295
1296 if (!renderTarget)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001297 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001298 ERR("Failed to retrieve the render target.");
1299 return error(GL_OUT_OF_MEMORY);
1300 }
1301
1302 bool redefined = redefineTexture(level, internalFormat, width, height, mType);
1303
1304 if (!isRenderableFormat())
1305 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001306 copyNonRenderable(&mImageArray[level], internalFormat, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001307 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001308 else
1309 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001310 if (redefined)
1311 {
1312 convertToRenderTarget();
1313 pushTexture(mTexture, true);
1314 }
1315 else
1316 {
1317 needRenderTarget();
1318 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001319
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001320 if (width != 0 && height != 0 && level < levelCount())
1321 {
1322 RECT sourceRect;
1323 sourceRect.left = x;
1324 sourceRect.right = x + width;
1325 sourceRect.top = y;
1326 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001327
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001328 IDirect3DSurface9 *dest;
1329 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001330
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001331 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1332 dest->Release();
1333 }
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001334 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001335
1336 mImageArray[level].width = width;
1337 mImageArray[level].height = height;
1338 mImageArray[level].format = internalFormat;
1339}
1340
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001341void 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 +00001342{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001343 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1344 {
1345 return error(GL_INVALID_VALUE);
1346 }
1347
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001348 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1349
1350 if (!renderTarget)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001351 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001352 ERR("Failed to retrieve the render target.");
1353 return error(GL_OUT_OF_MEMORY);
1354 }
1355
1356 bool redefined = redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, mType);
1357
1358 if (!isRenderableFormat())
1359 {
1360 copyNonRenderable(&mImageArray[level], getFormat(), xoffset, yoffset, x, y, width, height, renderTarget);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001361 }
1362 else
1363 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001364 if (redefined)
1365 {
1366 convertToRenderTarget();
1367 pushTexture(mTexture, true);
1368 }
1369 else
1370 {
1371 needRenderTarget();
1372 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001373
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001374 if (level < levelCount())
1375 {
1376 RECT sourceRect;
1377 sourceRect.left = x;
1378 sourceRect.right = x + width;
1379 sourceRect.top = y;
1380 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001381
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001382 IDirect3DSurface9 *dest;
1383 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001384
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001385 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
1386 dest->Release();
1387 }
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001388 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001389}
1390
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001391// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1392bool Texture2D::isComplete() const
1393{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001394 GLsizei width = mImageArray[0].width;
1395 GLsizei height = mImageArray[0].height;
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001396
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001397 if (width <= 0 || height <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001398 {
1399 return false;
1400 }
1401
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001402 bool mipmapping = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001403
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001404 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001405 {
1406 case GL_NEAREST:
1407 case GL_LINEAR:
1408 mipmapping = false;
1409 break;
1410 case GL_NEAREST_MIPMAP_NEAREST:
1411 case GL_LINEAR_MIPMAP_NEAREST:
1412 case GL_NEAREST_MIPMAP_LINEAR:
1413 case GL_LINEAR_MIPMAP_LINEAR:
1414 mipmapping = true;
1415 break;
1416 default: UNREACHABLE();
1417 }
1418
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001419 if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1420 (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1421 {
1422 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1423 {
1424 return false;
1425 }
1426 }
1427
1428
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001429 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1430 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1431 {
1432 return false;
1433 }
1434
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001435 if (mipmapping)
1436 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001437 if (!isPow2(width) || !isPow2(height))
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001438 {
1439 return false;
1440 }
1441
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001442 int q = log2(std::max(width, height));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001443
1444 for (int level = 1; level <= q; level++)
1445 {
1446 if (mImageArray[level].format != mImageArray[0].format)
1447 {
1448 return false;
1449 }
1450
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001451 if (mImageArray[level].width != std::max(1, width >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001452 {
1453 return false;
1454 }
1455
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001456 if (mImageArray[level].height != std::max(1, height >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001457 {
1458 return false;
1459 }
1460 }
1461 }
1462
1463 return true;
1464}
1465
daniel@transgaming.com01868132010-08-24 19:21:17 +00001466bool Texture2D::isCompressed() const
1467{
1468 return IsCompressed(getFormat());
1469}
1470
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001471// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001472IDirect3DBaseTexture9 *Texture2D::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001473{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001474 IDirect3DTexture9 *texture;
1475
1476 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001477 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001478
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001479 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001480
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001481 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001482 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001483 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001484 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001485 }
1486
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001487 if (mTexture) mTexture->Release();
1488 mTexture = texture;
1489 return texture;
1490}
1491
1492void Texture2D::updateTexture()
1493{
1494 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001495
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001496 int levels = levelCount();
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001497
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001498 for (int level = 0; level < levels; level++)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001499 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001500 if (mImageArray[level].dirty)
1501 {
1502 IDirect3DSurface9 *levelSurface = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001503 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001504
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001505 ASSERT(SUCCEEDED(result));
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001506
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001507 if (SUCCEEDED(result))
1508 {
1509 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1510 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001511
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001512 levelSurface->Release();
1513
1514 mImageArray[level].dirty = false;
1515 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001516 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001517 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001518}
1519
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001520IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001521{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001522 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001523
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001524 if (mWidth != 0 && mHeight != 0)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001525 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001526 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001527 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001528 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001529
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001530 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 +00001531
1532 if (FAILED(result))
1533 {
1534 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1535 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1536 }
1537
1538 if (mTexture != NULL)
1539 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001540 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001541 for (int i = 0; i < levels; i++)
1542 {
1543 IDirect3DSurface9 *source;
1544 result = mTexture->GetSurfaceLevel(i, &source);
1545
1546 if (FAILED(result))
1547 {
1548 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1549
1550 texture->Release();
1551
1552 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1553 }
1554
1555 IDirect3DSurface9 *dest;
1556 result = texture->GetSurfaceLevel(i, &dest);
1557
1558 if (FAILED(result))
1559 {
1560 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1561
1562 texture->Release();
1563 source->Release();
1564
1565 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1566 }
1567
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001568 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001569 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1570
1571 if (FAILED(result))
1572 {
1573 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1574
1575 texture->Release();
1576 source->Release();
1577 dest->Release();
1578
1579 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1580 }
1581
1582 source->Release();
1583 dest->Release();
1584 }
1585 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001586 }
1587
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001588 if (mTexture != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001589 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001590 mTexture->Release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001591 }
1592
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001593 mTexture = texture;
1594 return mTexture;
1595}
1596
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001597bool Texture2D::dirtyImageData() const
1598{
1599 int q = log2(std::max(mWidth, mHeight));
1600
1601 for (int i = 0; i <= q; i++)
1602 {
1603 if (mImageArray[i].dirty) return true;
1604 }
1605
1606 return false;
1607}
1608
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001609void Texture2D::generateMipmaps()
1610{
1611 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1612 {
1613 return error(GL_INVALID_OPERATION);
1614 }
1615
1616 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1617 unsigned int q = log2(std::max(mWidth, mHeight));
1618 for (unsigned int i = 1; i <= q; i++)
1619 {
1620 if (mImageArray[i].surface != NULL)
1621 {
1622 mImageArray[i].surface->Release();
1623 mImageArray[i].surface = NULL;
1624 }
1625
1626 mImageArray[i].dirty = false;
1627
1628 mImageArray[i].format = mImageArray[0].format;
1629 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1630 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
1631 }
1632
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00001633 if (isRenderable())
apatrick@chromium.org9398a6b2010-09-20 19:07:49 +00001634 {
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00001635 if (mTexture == NULL)
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001636 {
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00001637 ERR(" failed because mTexture was null.");
1638 return;
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001639 }
1640
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00001641 for (unsigned int i = 1; i <= q; i++)
1642 {
1643 IDirect3DSurface9 *upper = NULL;
1644 IDirect3DSurface9 *lower = NULL;
1645
1646 mTexture->GetSurfaceLevel(i-1, &upper);
1647 mTexture->GetSurfaceLevel(i, &lower);
1648
1649 if (upper != NULL && lower != NULL)
1650 {
1651 getBlitter()->boxFilter(upper, lower);
1652 }
1653
1654 if (upper != NULL) upper->Release();
1655 if (lower != NULL) lower->Release();
1656 }
1657 }
1658 else
1659 {
1660 for (unsigned int i = 1; i <= q; i++)
1661 {
1662 createSurface(mImageArray[i].width, mImageArray[i].height, mImageArray[i].format, mType, &mImageArray[i]);
1663 if (mImageArray[i].surface == NULL)
1664 {
1665 return error(GL_OUT_OF_MEMORY);
1666 }
1667
1668 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1669 {
1670 ERR(" failed to load filter %d to %d.", i - 1, i);
1671 }
1672
1673 mImageArray[i].dirty = true;
1674 }
1675
1676 mDirtyMetaData = true;
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001677 }
1678}
1679
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001680Renderbuffer *Texture2D::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001681{
1682 if (target != GL_TEXTURE_2D)
1683 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001684 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001685 }
1686
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001687 if (mColorbufferProxy.get() == NULL)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001688 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001689 mColorbufferProxy.set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001690 }
1691
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001692 return mColorbufferProxy.get();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001693}
1694
1695IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1696{
1697 ASSERT(target == GL_TEXTURE_2D);
1698
1699 needRenderTarget();
1700
apatrick@chromium.org4d5962c2010-09-20 19:02:30 +00001701 if (mTexture == NULL)
1702 {
1703 return NULL;
1704 }
1705
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001706 IDirect3DSurface9 *renderTarget = NULL;
1707 mTexture->GetSurfaceLevel(0, &renderTarget);
1708
1709 return renderTarget;
1710}
1711
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001712TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001713{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001714 mTexture = NULL;
1715}
1716
1717TextureCubeMap::~TextureCubeMap()
1718{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001719 for (int i = 0; i < 6; i++)
1720 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001721 mFaceProxies[i].set(NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001722 }
1723
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001724 if (mTexture)
1725 {
1726 mTexture->Release();
1727 mTexture = NULL;
1728 }
1729}
1730
1731GLenum TextureCubeMap::getTarget() const
1732{
1733 return GL_TEXTURE_CUBE_MAP;
1734}
1735
daniel@transgaming.com01868132010-08-24 19:21:17 +00001736GLenum TextureCubeMap::getFormat() const
1737{
1738 return mImageArray[0][0].format;
1739}
1740
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001741void 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 +00001742{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001743 setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001744}
1745
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001746void 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 +00001747{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001748 setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001749}
1750
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001751void 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 +00001752{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001753 setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001754}
1755
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001756void 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 +00001757{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001758 setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001759}
1760
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001761void 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 +00001762{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001763 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001764}
1765
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001766void 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 +00001767{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001768 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001769}
1770
daniel@transgaming.com01868132010-08-24 19:21:17 +00001771void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1772{
1773 redefineTexture(level, internalFormat, width);
1774
1775 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[faceIndex(face)][level]);
1776}
1777
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001778void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1779{
1780 int face = faceIndex(faceTarget);
1781
1782 ASSERT(mImageArray[face][level].surface != NULL);
1783
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001784 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001785 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001786 IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level);
1787 ASSERT(destLevel != NULL);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001788
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001789 if (destLevel != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001790 {
1791 Image *img = &mImageArray[face][level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001792
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001793 RECT sourceRect;
1794 sourceRect.left = xoffset;
1795 sourceRect.top = yoffset;
1796 sourceRect.right = xoffset + width;
1797 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001798
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001799 POINT destPoint;
1800 destPoint.x = xoffset;
1801 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001802
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001803 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001804 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001805
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001806 destLevel->Release();
1807
1808 img->dirty = false;
1809 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001810 }
1811}
1812
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001813void 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 +00001814{
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001815 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
daniel@transgaming.com31273552010-08-04 13:42:44 +00001816 {
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001817 commitRect(target, level, xoffset, yoffset, width, height);
daniel@transgaming.com31273552010-08-04 13:42:44 +00001818 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001819}
1820
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001821void 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 +00001822{
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001823 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
daniel@transgaming.com01868132010-08-24 19:21:17 +00001824 {
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001825 commitRect(target, level, xoffset, yoffset, width, height);
daniel@transgaming.com01868132010-08-24 19:21:17 +00001826 }
1827}
1828
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001829// 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 +00001830bool TextureCubeMap::isComplete() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001831{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001832 int size = mImageArray[0][0].width;
1833
1834 if (size <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001835 {
1836 return false;
1837 }
1838
1839 bool mipmapping;
1840
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001841 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001842 {
1843 case GL_NEAREST:
1844 case GL_LINEAR:
1845 mipmapping = false;
1846 break;
1847 case GL_NEAREST_MIPMAP_NEAREST:
1848 case GL_LINEAR_MIPMAP_NEAREST:
1849 case GL_NEAREST_MIPMAP_LINEAR:
1850 case GL_LINEAR_MIPMAP_LINEAR:
1851 mipmapping = true;
1852 break;
1853 default: UNREACHABLE();
1854 }
1855
1856 for (int face = 0; face < 6; face++)
1857 {
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001858 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001859 {
1860 return false;
1861 }
1862 }
1863
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001864 if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1865 (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1866 {
1867 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1868 {
1869 return false;
1870 }
1871 }
1872
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001873 if (mipmapping)
1874 {
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001875 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1876 {
1877 return false;
1878 }
1879
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001880 int q = log2(size);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001881
1882 for (int face = 0; face < 6; face++)
1883 {
1884 for (int level = 1; level <= q; level++)
1885 {
1886 if (mImageArray[face][level].format != mImageArray[0][0].format)
1887 {
1888 return false;
1889 }
1890
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001891 if (mImageArray[face][level].width != std::max(1, size >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001892 {
1893 return false;
1894 }
1895
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001896 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001897 }
1898 }
1899 }
1900
1901 return true;
1902}
1903
daniel@transgaming.com01868132010-08-24 19:21:17 +00001904bool TextureCubeMap::isCompressed() const
1905{
1906 return IsCompressed(getFormat());
1907}
1908
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001909// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001910IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001911{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001912 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001913 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001914
1915 IDirect3DCubeTexture9 *texture;
1916
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001917 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001918
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001919 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001920 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001921 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001922 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001923 }
1924
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001925 if (mTexture) mTexture->Release();
1926
1927 mTexture = texture;
1928 return mTexture;
1929}
1930
1931void TextureCubeMap::updateTexture()
1932{
1933 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001934
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001935 for (int face = 0; face < 6; face++)
1936 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001937 int levels = levelCount();
1938 for (int level = 0; level < levels; level++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001939 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001940 Image *img = &mImageArray[face][level];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001941
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001942 if (img->dirty)
1943 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001944 IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level);
1945 ASSERT(levelSurface != NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001946
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001947 if (levelSurface != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001948 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001949 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001950 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001951
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001952 levelSurface->Release();
1953
1954 img->dirty = false;
1955 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001956 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001957 }
1958 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001959}
1960
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001961IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
1962{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001963 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001964
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001965 if (mWidth != 0)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001966 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001967 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001968 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001969 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001970
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001971 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001972
1973 if (FAILED(result))
1974 {
1975 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1976 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1977 }
1978
1979 if (mTexture != NULL)
1980 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001981 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001982 for (int f = 0; f < 6; f++)
1983 {
1984 for (int i = 0; i < levels; i++)
1985 {
1986 IDirect3DSurface9 *source;
1987 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
1988
1989 if (FAILED(result))
1990 {
1991 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1992
1993 texture->Release();
1994
1995 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1996 }
1997
1998 IDirect3DSurface9 *dest;
1999 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2000
2001 if (FAILED(result))
2002 {
2003 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2004
2005 texture->Release();
2006 source->Release();
2007
2008 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
2009 }
2010
daniel@transgaming.comae072af2010-05-05 18:47:28 +00002011 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002012 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2013
2014 if (FAILED(result))
2015 {
2016 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2017
2018 texture->Release();
2019 source->Release();
2020 dest->Release();
2021
2022 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
2023 }
2024 }
2025 }
2026 }
daniel@transgaming.com7051b972010-03-21 04:31:07 +00002027 }
2028
2029 if (mTexture != NULL)
2030 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00002031 mTexture->Release();
2032 }
2033
2034 mTexture = texture;
2035 return mTexture;
2036}
2037
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00002038void 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 +00002039{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002040 redefineTexture(level, internalFormat, width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002041
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002042 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002043}
daniel@transgaming.com00c75962010-03-11 20:36:15 +00002044
2045unsigned int TextureCubeMap::faceIndex(GLenum face)
2046{
2047 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2048 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2049 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2050 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2051 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2052
2053 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2054}
2055
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00002056bool TextureCubeMap::dirtyImageData() const
2057{
2058 int q = log2(mWidth);
2059
2060 for (int f = 0; f < 6; f++)
2061 {
2062 for (int i = 0; i <= q; i++)
2063 {
2064 if (mImageArray[f][i].dirty) return true;
2065 }
2066 }
2067
2068 return false;
2069}
2070
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002071// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
2072// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
2073// Call this when a particular level of the texture must be defined with a specific format, width and height.
2074//
2075// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
2076// a new size for the texture by working backwards from the given size.
2077bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
2078{
2079 // Are these settings compatible with level 0?
2080 bool sizeOkay = (mImageArray[0][0].width >> level == width);
2081
2082 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
2083
2084 if (!textureOkay)
2085 {
2086 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
2087 mImageArray[0][0].format, mImageArray[0][0].width,
2088 internalFormat, width);
2089
2090 // Purge all the levels and the texture.
daniel@transgaming.com5d752f22010-10-07 13:37:20 +00002091 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002092 {
2093 for (int f = 0; f < 6; f++)
2094 {
2095 if (mImageArray[f][i].surface != NULL)
2096 {
2097 mImageArray[f][i].dirty = false;
2098
2099 mImageArray[f][i].surface->Release();
2100 mImageArray[f][i].surface = NULL;
2101 }
2102 }
2103 }
2104
2105 if (mTexture != NULL)
2106 {
2107 mTexture->Release();
2108 mTexture = NULL;
2109 dropTexture();
2110 }
2111
2112 mWidth = width << level;
2113 mImageArray[0][0].width = width << level;
2114 mHeight = width << level;
2115 mImageArray[0][0].height = width << level;
2116
2117 mImageArray[0][0].format = internalFormat;
2118 }
2119
2120 return !textureOkay;
2121}
2122
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00002123void 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 +00002124{
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002125 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002126
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002127 if (!renderTarget)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002128 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002129 ERR("Failed to retrieve the render target.");
2130 return error(GL_OUT_OF_MEMORY);
2131 }
2132
2133 unsigned int faceindex = faceIndex(target);
2134 bool redefined = redefineTexture(level, internalFormat, width);
2135
2136 if (!isRenderableFormat())
2137 {
2138 copyNonRenderable(&mImageArray[faceindex][level], internalFormat, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002139 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00002140 else
2141 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002142 if (redefined)
2143 {
2144 convertToRenderTarget();
2145 pushTexture(mTexture, true);
2146 }
2147 else
2148 {
2149 needRenderTarget();
2150 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002151
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002152 ASSERT(width == height);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002153
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002154 if (width > 0 && level < levelCount())
2155 {
2156 RECT sourceRect;
2157 sourceRect.left = x;
2158 sourceRect.right = x + width;
2159 sourceRect.top = y;
2160 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002161
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002162 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002163
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002164 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
2165 dest->Release();
2166 }
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002167 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002168
2169 mImageArray[faceindex][level].width = width;
2170 mImageArray[faceindex][level].height = height;
2171 mImageArray[faceindex][level].format = internalFormat;
2172}
2173
2174IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(unsigned int faceIdentifier, unsigned int level)
2175{
2176 unsigned int faceIndex;
2177
2178 if (faceIdentifier < 6)
2179 {
2180 faceIndex = faceIdentifier;
2181 }
2182 else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
2183 {
2184 faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2185 }
2186 else
2187 {
2188 UNREACHABLE();
2189 faceIndex = 0;
2190 }
2191
2192 if (mTexture == NULL)
2193 {
2194 UNREACHABLE();
2195 return NULL;
2196 }
2197
2198 IDirect3DSurface9 *surface = NULL;
2199
2200 HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface);
2201
2202 return (SUCCEEDED(hr)) ? surface : NULL;
2203}
2204
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00002205void 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 +00002206{
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00002207 GLsizei size = mImageArray[faceIndex(target)][level].width;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002208
2209 if (xoffset + width > size || yoffset + height > size)
2210 {
2211 return error(GL_INVALID_VALUE);
2212 }
2213
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002214 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2215
2216 if (!renderTarget)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002217 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002218 ERR("Failed to retrieve the render target.");
2219 return error(GL_OUT_OF_MEMORY);
2220 }
2221
2222 unsigned int faceindex = faceIndex(target);
2223 bool redefined = redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width);
2224
2225 if (!isRenderableFormat())
2226 {
2227 copyNonRenderable(&mImageArray[faceindex][level], getFormat(), 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002228 }
2229 else
2230 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002231 if (redefined)
2232 {
2233 convertToRenderTarget();
2234 pushTexture(mTexture, true);
2235 }
2236 else
2237 {
2238 needRenderTarget();
2239 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002240
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002241 if (level < levelCount())
2242 {
2243 RECT sourceRect;
2244 sourceRect.left = x;
2245 sourceRect.right = x + width;
2246 sourceRect.top = y;
2247 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002248
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002249 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002250
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002251 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
2252 dest->Release();
2253 }
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00002254 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002255}
2256
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00002257bool TextureCubeMap::isCubeComplete() const
2258{
2259 if (mImageArray[0][0].width == 0)
2260 {
2261 return false;
2262 }
2263
2264 for (unsigned int f = 1; f < 6; f++)
2265 {
2266 if (mImageArray[f][0].width != mImageArray[0][0].width
2267 || mImageArray[f][0].format != mImageArray[0][0].format)
2268 {
2269 return false;
2270 }
2271 }
2272
2273 return true;
2274}
2275
2276void TextureCubeMap::generateMipmaps()
2277{
2278 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
2279 {
2280 return error(GL_INVALID_OPERATION);
2281 }
2282
2283 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2284 unsigned int q = log2(mImageArray[0][0].width);
2285 for (unsigned int f = 0; f < 6; f++)
2286 {
2287 for (unsigned int i = 1; i <= q; i++)
2288 {
2289 if (mImageArray[f][i].surface != NULL)
2290 {
2291 mImageArray[f][i].surface->Release();
2292 mImageArray[f][i].surface = NULL;
2293 }
2294
2295 mImageArray[f][i].dirty = false;
2296
2297 mImageArray[f][i].format = mImageArray[f][0].format;
2298 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2299 mImageArray[f][i].height = mImageArray[f][i].width;
2300 }
2301 }
2302
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00002303 if (isRenderable())
apatrick@chromium.org9398a6b2010-09-20 19:07:49 +00002304 {
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00002305 if (mTexture == NULL)
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00002306 {
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00002307 return;
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00002308 }
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00002309
2310 for (unsigned int f = 0; f < 6; f++)
2311 {
2312 for (unsigned int i = 1; i <= q; i++)
2313 {
2314 IDirect3DSurface9 *upper = getCubeMapSurface(f, i-1);
2315 IDirect3DSurface9 *lower = getCubeMapSurface(f, i);
2316
2317 if (upper != NULL && lower != NULL)
2318 {
2319 getBlitter()->boxFilter(upper, lower);
2320 }
2321
2322 if (upper != NULL) upper->Release();
2323 if (lower != NULL) lower->Release();
2324 }
2325 }
2326 }
2327 else
2328 {
2329 for (unsigned int f = 0; f < 6; f++)
2330 {
2331 for (unsigned int i = 1; i <= q; i++)
2332 {
2333 createSurface(mImageArray[f][i].width, mImageArray[f][i].height, mImageArray[f][i].format, mType, &mImageArray[f][i]);
2334 if (mImageArray[f][i].surface == NULL)
2335 {
2336 return error(GL_OUT_OF_MEMORY);
2337 }
2338
2339 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2340 {
2341 ERR(" failed to load filter %d to %d.", i - 1, i);
2342 }
2343
2344 mImageArray[f][i].dirty = true;
2345 }
2346 }
2347
2348 mDirtyMetaData = true;
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00002349 }
2350}
2351
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002352Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002353{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002354 if (!IsCubemapTextureTarget(target))
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002355 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002356 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002357 }
2358
2359 unsigned int face = faceIndex(target);
2360
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002361 if (mFaceProxies[face].get() == NULL)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002362 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002363 mFaceProxies[face].set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002364 }
2365
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002366 return mFaceProxies[face].get();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002367}
2368
2369IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2370{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002371 ASSERT(IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002372
2373 needRenderTarget();
daniel@transgaming.come979ead2010-09-23 18:03:14 +00002374
2375 if (mTexture == NULL)
2376 {
2377 return NULL;
apatrick@chromium.org4d5962c2010-09-20 19:02:30 +00002378 }
2379
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002380 IDirect3DSurface9 *renderTarget = NULL;
2381 mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex(target)), 0, &renderTarget);
2382
2383 return renderTarget;
2384}
2385
2386Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
enne@chromium.org0fa74632010-09-21 16:18:52 +00002387 : Colorbuffer(texture), mTexture(texture), mTarget(target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002388{
daniel@transgaming.comedc19182010-10-15 17:57:55 +00002389 ASSERT(IsTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002390}
2391
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002392void Texture::TextureColorbufferProxy::addRef() const
2393{
2394 mTexture->addRef();
2395}
2396
2397void Texture::TextureColorbufferProxy::release() const
2398{
2399 mTexture->release();
2400}
2401
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002402IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
2403{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002404 if (mRenderTarget) mRenderTarget->Release();
2405
2406 mRenderTarget = mTexture->getRenderTarget(mTarget);
2407
2408 return mRenderTarget;
2409}
2410
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002411int Texture::TextureColorbufferProxy::getWidth() const
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002412{
daniel@transgaming.com866f3182010-05-20 19:28:22 +00002413 return mTexture->getWidth();
2414}
2415
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002416int Texture::TextureColorbufferProxy::getHeight() const
daniel@transgaming.com866f3182010-05-20 19:28:22 +00002417{
2418 return mTexture->getHeight();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002419}
2420
daniel@transgaming.com01868132010-08-24 19:21:17 +00002421GLenum Texture::TextureColorbufferProxy::getFormat() const
2422{
2423 return mTexture->getFormat();
2424}
2425
daniel@transgaming.com1297d922010-09-01 15:47:47 +00002426bool Texture::TextureColorbufferProxy::isFloatingPoint() const
2427{
2428 return mTexture->isFloatingPoint();
2429}
2430
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002431}