blob: ea81166ea449de608acc75a044fd8828dd5c5743 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Texture.cpp: Implements the gl::Texture class and its derived classes
8// Texture2D and TextureCubeMap. Implements GL texture objects and related
9// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
10
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000011#include "libGLESv2/Texture.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000012
daniel@transgaming.com16973022010-03-11 19:22:19 +000013#include <algorithm>
14
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000015#include "common/debug.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000016
17#include "libGLESv2/main.h"
18#include "libGLESv2/mathutil.h"
19#include "libGLESv2/utilities.h"
20#include "libGLESv2/Blit.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000021
22namespace gl
23{
daniel@transgaming.com842f7a42010-03-21 04:31:03 +000024
25Texture::Image::Image()
daniel@transgaming.com01868132010-08-24 19:21:17 +000026 : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +000027{
28}
29
30Texture::Image::~Image()
31{
32 if (surface) surface->Release();
33}
34
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000035Texture::Texture(GLuint id) : RefCountObject(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000036{
37 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
38 mMagFilter = GL_LINEAR;
39 mWrapS = GL_REPEAT;
40 mWrapT = GL_REPEAT;
daniel@transgaming.com29d27002010-03-11 19:41:22 +000041
daniel@transgaming.com31273552010-08-04 13:42:44 +000042 mWidth = 0;
43 mHeight = 0;
44
daniel@transgaming.com00c75962010-03-11 20:36:15 +000045 mDirtyMetaData = true;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000046 mDirty = true;
daniel@transgaming.com93a81472010-04-20 18:52:58 +000047 mIsRenderable = false;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +000048 mType = GL_UNSIGNED_BYTE;
daniel@transgaming.com0a311a42010-05-17 09:58:33 +000049 mBaseTexture = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000050}
51
52Texture::~Texture()
53{
54}
55
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000056Blit *Texture::getBlitter()
57{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000058 Context *context = getContext();
59 return context->getBlitter();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000060}
61
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000062// Returns true on successful filter state update (valid enum parameter)
63bool Texture::setMinFilter(GLenum filter)
64{
65 switch (filter)
66 {
67 case GL_NEAREST:
68 case GL_LINEAR:
69 case GL_NEAREST_MIPMAP_NEAREST:
70 case GL_LINEAR_MIPMAP_NEAREST:
71 case GL_NEAREST_MIPMAP_LINEAR:
72 case GL_LINEAR_MIPMAP_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000073 {
74 if (mMinFilter != filter)
75 {
76 mMinFilter = filter;
77 mDirty = true;
78 }
79 return true;
80 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000081 default:
82 return false;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +000083 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000084}
85
86// Returns true on successful filter state update (valid enum parameter)
87bool Texture::setMagFilter(GLenum filter)
88{
89 switch (filter)
90 {
91 case GL_NEAREST:
92 case GL_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000093 {
94 if (mMagFilter != filter)
95 {
96 mMagFilter = filter;
97 mDirty = true;
98 }
99 return true;
100 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000101 default:
102 return false;
103 }
104}
105
106// Returns true on successful wrap state update (valid enum parameter)
107bool Texture::setWrapS(GLenum wrap)
108{
109 switch (wrap)
110 {
111 case GL_REPEAT:
112 case GL_CLAMP_TO_EDGE:
113 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000114 {
115 if (mWrapS != wrap)
116 {
117 mWrapS = wrap;
118 mDirty = true;
119 }
120 return true;
121 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000122 default:
123 return false;
124 }
125}
126
127// Returns true on successful wrap state update (valid enum parameter)
128bool Texture::setWrapT(GLenum wrap)
129{
130 switch (wrap)
131 {
132 case GL_REPEAT:
133 case GL_CLAMP_TO_EDGE:
134 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000135 {
136 if (mWrapT != wrap)
137 {
138 mWrapT = wrap;
139 mDirty = true;
140 }
141 return true;
142 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000143 default:
144 return false;
145 }
146}
147
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000148GLenum Texture::getMinFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000149{
150 return mMinFilter;
151}
152
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000153GLenum Texture::getMagFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000154{
155 return mMagFilter;
156}
157
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000158GLenum Texture::getWrapS() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000159{
160 return mWrapS;
161}
162
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000163GLenum Texture::getWrapT() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000164{
165 return mWrapT;
166}
167
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000168GLuint Texture::getWidth() const
169{
170 return mWidth;
171}
172
173GLuint Texture::getHeight() const
174{
175 return mHeight;
176}
177
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000178bool Texture::isFloatingPoint() const
179{
180 return (mType == GL_FLOAT || mType == GL_HALF_FLOAT_OES);
181}
182
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000183// Selects an internal Direct3D 9 format for storing an Image
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000184D3DFORMAT Texture::selectFormat(GLenum format, GLenum type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000185{
daniel@transgaming.com01868132010-08-24 19:21:17 +0000186 if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
187 format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
188 {
189 return D3DFMT_DXT1;
190 }
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000191 else if (type == GL_FLOAT)
192 {
193 return D3DFMT_A32B32G32R32F;
194 }
195 else if (type == GL_HALF_FLOAT_OES)
196 {
197 return D3DFMT_A16B16G16R16F;
198 }
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000199 else if (type == GL_UNSIGNED_BYTE)
daniel@transgaming.com01868132010-08-24 19:21:17 +0000200 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000201 if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
202 {
203 return D3DFMT_L8;
204 }
205 else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
206 {
207 return D3DFMT_A8L8;
208 }
209
daniel@transgaming.com01868132010-08-24 19:21:17 +0000210 return D3DFMT_A8R8G8B8;
211 }
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000212
213 return D3DFMT_A8R8G8B8;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000214}
215
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000216// 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 +0000217// into the target pixel rectangle at output with outputPitch bytes in between each line.
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000218void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000219 GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000220{
daniel@transgaming.com713914b2010-05-04 03:35:17 +0000221 GLsizei inputPitch = ComputePitch(width, format, type, unpackAlignment);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000222
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000223 switch (type)
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000224 {
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000225 case GL_UNSIGNED_BYTE:
226 switch (format)
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000227 {
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000228 case GL_ALPHA:
229 loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
230 break;
231 case GL_LUMINANCE:
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000232 loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000233 break;
234 case GL_LUMINANCE_ALPHA:
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000235 loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000236 break;
237 case GL_RGB:
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000238 loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
239 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000240 case GL_RGBA:
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000241 loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
242 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000243 case GL_BGRA_EXT:
244 loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000245 break;
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000246 default: UNREACHABLE();
247 }
248 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000249 case GL_UNSIGNED_SHORT_5_6_5:
250 switch (format)
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000251 {
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000252 case GL_RGB:
253 loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000254 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000255 default: UNREACHABLE();
256 }
257 break;
258 case GL_UNSIGNED_SHORT_4_4_4_4:
259 switch (format)
260 {
261 case GL_RGBA:
262 loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
263 break;
264 default: UNREACHABLE();
265 }
266 break;
267 case GL_UNSIGNED_SHORT_5_5_5_1:
268 switch (format)
269 {
270 case GL_RGBA:
271 loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
272 break;
273 default: UNREACHABLE();
274 }
275 break;
276 case GL_FLOAT:
277 switch (format)
278 {
279 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
280 case GL_ALPHA:
281 loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
282 break;
283 case GL_LUMINANCE:
284 loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
285 break;
286 case GL_LUMINANCE_ALPHA:
287 loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
288 break;
289 case GL_RGB:
290 loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
291 break;
292 case GL_RGBA:
293 loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
294 break;
295 default: UNREACHABLE();
296 }
297 break;
298 case GL_HALF_FLOAT_OES:
299 switch (format)
300 {
301 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
302 case GL_ALPHA:
303 loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
304 break;
305 case GL_LUMINANCE:
306 loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
307 break;
308 case GL_LUMINANCE_ALPHA:
309 loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
310 break;
311 case GL_RGB:
312 loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
313 break;
314 case GL_RGBA:
315 loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
316 break;
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000317 default: UNREACHABLE();
318 }
319 break;
320 default: UNREACHABLE();
321 }
322}
323
324void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
325 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
326{
327 const unsigned char *source = NULL;
328 unsigned char *dest = NULL;
329
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000330 for (int y = 0; y < height; y++)
331 {
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000332 source = static_cast<const unsigned char*>(input) + y * inputPitch;
333 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000334 for (int x = 0; x < width; x++)
335 {
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000336 dest[4 * x + 0] = 0;
337 dest[4 * x + 1] = 0;
338 dest[4 * x + 2] = 0;
339 dest[4 * x + 3] = source[x];
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000340 }
341 }
342}
343
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000344void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
345 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
346{
347 const float *source = NULL;
348 float *dest = NULL;
349
350 for (int y = 0; y < height; y++)
351 {
352 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
353 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
354 for (int x = 0; x < width; x++)
355 {
356 dest[4 * x + 0] = 0;
357 dest[4 * x + 1] = 0;
358 dest[4 * x + 2] = 0;
359 dest[4 * x + 3] = source[x];
360 }
361 }
362}
363
364void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
365 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
366{
367 const unsigned short *source = NULL;
368 unsigned short *dest = NULL;
369
370 for (int y = 0; y < height; y++)
371 {
372 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
373 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
374 for (int x = 0; x < width; x++)
375 {
376 dest[4 * x + 0] = 0;
377 dest[4 * x + 1] = 0;
378 dest[4 * x + 2] = 0;
379 dest[4 * x + 3] = source[x];
380 }
381 }
382}
383
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000384void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000385 size_t inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000386{
387 const unsigned char *source = NULL;
388 unsigned char *dest = NULL;
389
390 for (int y = 0; y < height; y++)
391 {
392 source = static_cast<const unsigned char*>(input) + y * inputPitch;
393 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000394
395 if (!native) // BGRA8 destination format
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000396 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000397 for (int x = 0; x < width; x++)
398 {
399 dest[4 * x + 0] = source[x];
400 dest[4 * x + 1] = source[x];
401 dest[4 * x + 2] = source[x];
402 dest[4 * x + 3] = 0xFF;
403 }
404 }
405 else // L8 destination format
406 {
407 memcpy(dest, source, width);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000408 }
409 }
410}
411
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000412void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
413 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
414{
415 const float *source = NULL;
416 float *dest = NULL;
417
418 for (int y = 0; y < height; y++)
419 {
420 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
421 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
422 for (int x = 0; x < width; x++)
423 {
424 dest[4 * x + 0] = source[x];
425 dest[4 * x + 1] = source[x];
426 dest[4 * x + 2] = source[x];
427 dest[4 * x + 3] = 1.0f;
428 }
429 }
430}
431
432void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
433 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
434{
435 const unsigned short *source = NULL;
436 unsigned short *dest = NULL;
437
438 for (int y = 0; y < height; y++)
439 {
440 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
441 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
442 for (int x = 0; x < width; x++)
443 {
444 dest[4 * x + 0] = source[x];
445 dest[4 * x + 1] = source[x];
446 dest[4 * x + 2] = source[x];
447 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
448 }
449 }
450}
451
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000452void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000453 size_t inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000454{
455 const unsigned char *source = NULL;
456 unsigned char *dest = NULL;
457
458 for (int y = 0; y < height; y++)
459 {
460 source = static_cast<const unsigned char*>(input) + y * inputPitch;
461 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000462
463 if (!native) // BGRA8 destination format
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000464 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000465 for (int x = 0; x < width; x++)
466 {
467 dest[4 * x + 0] = source[2*x+0];
468 dest[4 * x + 1] = source[2*x+0];
469 dest[4 * x + 2] = source[2*x+0];
470 dest[4 * x + 3] = source[2*x+1];
471 }
472 }
473 else
474 {
475 memcpy(dest, source, width * 2);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000476 }
477 }
478}
479
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000480void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
481 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
482{
483 const float *source = NULL;
484 float *dest = NULL;
485
486 for (int y = 0; y < height; y++)
487 {
488 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
489 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
490 for (int x = 0; x < width; x++)
491 {
492 dest[4 * x + 0] = source[2*x+0];
493 dest[4 * x + 1] = source[2*x+0];
494 dest[4 * x + 2] = source[2*x+0];
495 dest[4 * x + 3] = source[2*x+1];
496 }
497 }
498}
499
500void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
501 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
502{
503 const unsigned short *source = NULL;
504 unsigned short *dest = NULL;
505
506 for (int y = 0; y < height; y++)
507 {
508 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
509 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
510 for (int x = 0; x < width; x++)
511 {
512 dest[4 * x + 0] = source[2*x+0];
513 dest[4 * x + 1] = source[2*x+0];
514 dest[4 * x + 2] = source[2*x+0];
515 dest[4 * x + 3] = source[2*x+1];
516 }
517 }
518}
519
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000520void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
521 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
522{
523 const unsigned char *source = NULL;
524 unsigned char *dest = NULL;
525
526 for (int y = 0; y < height; y++)
527 {
528 source = static_cast<const unsigned char*>(input) + y * inputPitch;
529 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
530 for (int x = 0; x < width; x++)
531 {
532 dest[4 * x + 0] = source[x * 3 + 2];
533 dest[4 * x + 1] = source[x * 3 + 1];
534 dest[4 * x + 2] = source[x * 3 + 0];
535 dest[4 * x + 3] = 0xFF;
536 }
537 }
538}
539
540void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
541 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
542{
543 const unsigned short *source = NULL;
544 unsigned char *dest = NULL;
545
546 for (int y = 0; y < height; y++)
547 {
548 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
549 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
550 for (int x = 0; x < width; x++)
551 {
552 unsigned short rgba = source[x];
553 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
554 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
555 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
556 dest[4 * x + 3] = 0xFF;
557 }
558 }
559}
560
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000561void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
562 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
563{
564 const float *source = NULL;
565 float *dest = NULL;
566
567 for (int y = 0; y < height; y++)
568 {
569 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
570 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
571 for (int x = 0; x < width; x++)
572 {
573 dest[4 * x + 0] = source[x * 3 + 0];
574 dest[4 * x + 1] = source[x * 3 + 1];
575 dest[4 * x + 2] = source[x * 3 + 2];
576 dest[4 * x + 3] = 1.0f;
577 }
578 }
579}
580
581void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
582 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
583{
584 const unsigned short *source = NULL;
585 unsigned short *dest = NULL;
586
587 for (int y = 0; y < height; y++)
588 {
589 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
590 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
591 for (int x = 0; x < width; x++)
592 {
593 dest[4 * x + 0] = source[x * 3 + 0];
594 dest[4 * x + 1] = source[x * 3 + 1];
595 dest[4 * x + 2] = source[x * 3 + 2];
596 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
597 }
598 }
599}
600
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000601void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
602 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
603{
604 const unsigned char *source = NULL;
605 unsigned char *dest = NULL;
606
607 for (int y = 0; y < height; y++)
608 {
609 source = static_cast<const unsigned char*>(input) + y * inputPitch;
610 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
611 for (int x = 0; x < width; x++)
612 {
613 dest[4 * x + 0] = source[x * 4 + 2];
614 dest[4 * x + 1] = source[x * 4 + 1];
615 dest[4 * x + 2] = source[x * 4 + 0];
616 dest[4 * x + 3] = source[x * 4 + 3];
617 }
618 }
619}
620
621void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
622 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
623{
624 const unsigned short *source = NULL;
625 unsigned char *dest = NULL;
626
627 for (int y = 0; y < height; y++)
628 {
629 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
630 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
631 for (int x = 0; x < width; x++)
632 {
633 unsigned short rgba = source[x];
634 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
635 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
636 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
637 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
638 }
639 }
640}
641
642void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
643 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
644{
645 const unsigned short *source = NULL;
646 unsigned char *dest = NULL;
647
648 for (int y = 0; y < height; y++)
649 {
650 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
651 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
652 for (int x = 0; x < width; x++)
653 {
654 unsigned short rgba = source[x];
655 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
656 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
657 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
658 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
659 }
660 }
661}
662
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000663void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
664 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
665{
666 const float *source = NULL;
667 float *dest = NULL;
668
669 for (int y = 0; y < height; y++)
670 {
671 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
672 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
673 memcpy(dest, source, width * 16);
674 }
675}
676
677void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
678 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
679{
680 const unsigned char *source = NULL;
681 unsigned char *dest = NULL;
682
683 for (int y = 0; y < height; y++)
684 {
685 source = static_cast<const unsigned char*>(input) + y * inputPitch;
686 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
687 memcpy(dest, source, width * 8);
688 }
689}
690
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000691void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
692 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
693{
694 const unsigned char *source = NULL;
695 unsigned char *dest = NULL;
696
697 for (int y = 0; y < height; y++)
698 {
699 source = static_cast<const unsigned char*>(input) + y * inputPitch;
700 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
701 memcpy(dest, source, width*4);
702 }
703}
704
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000705void Texture::createSurface(GLsizei width, GLsizei height, GLenum format, GLenum type, Image *img)
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000706{
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000707 IDirect3DTexture9 *newTexture = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000708 IDirect3DSurface9 *newSurface = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000709
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000710 if (width != 0 && height != 0)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000711 {
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000712 int levelToFetch = 0;
713 GLsizei requestWidth = width;
714 GLsizei requestHeight = height;
715 if (IsCompressed(format) && (width % 4 != 0 || height % 4 != 0))
716 {
717 bool isMult4 = false;
718 int upsampleCount = 0;
719 while (!isMult4)
720 {
721 requestWidth <<= 1;
722 requestHeight <<= 1;
723 upsampleCount++;
724 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
725 {
726 isMult4 = true;
727 }
728 }
729 levelToFetch = upsampleCount;
730 }
731
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000732 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, selectFormat(format, type),
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000733 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000734
735 if (FAILED(result))
736 {
737 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
738 return error(GL_OUT_OF_MEMORY);
739 }
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000740
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000741 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000742 newTexture->Release();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000743 }
744
745 if (img->surface) img->surface->Release();
746 img->surface = newSurface;
747
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000748 img->width = width;
749 img->height = height;
750 img->format = format;
daniel@transgaming.com01868132010-08-24 19:21:17 +0000751}
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000752
daniel@transgaming.com01868132010-08-24 19:21:17 +0000753void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
754{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000755 createSurface(width, height, format, type, img);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000756
757 if (pixels != NULL && img->surface != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000758 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000759 D3DSURFACE_DESC description;
760 img->surface->GetDesc(&description);
761
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000762 D3DLOCKED_RECT locked;
daniel@transgaming.com01868132010-08-24 19:21:17 +0000763 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000764
765 ASSERT(SUCCEEDED(result));
766
767 if (SUCCEEDED(result))
768 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000769 loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000770 img->surface->UnlockRect();
771 }
772
773 img->dirty = true;
774 }
775
776 mDirtyMetaData = true;
777}
778
779void Texture::setCompressedImage(GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
780{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000781 createSurface(width, height, format, GL_UNSIGNED_BYTE, img);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000782
783 if (pixels != NULL && img->surface != NULL)
784 {
785 D3DLOCKED_RECT locked;
786 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
787
788 ASSERT(SUCCEEDED(result));
789
790 if (SUCCEEDED(result))
791 {
792 memcpy(locked.pBits, pixels, imageSize);
793 img->surface->UnlockRect();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000794 }
795
796 img->dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000797 }
798
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000799 mDirtyMetaData = true;
800}
801
daniel@transgaming.com31273552010-08-04 13:42:44 +0000802bool 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 +0000803{
daniel@transgaming.com31273552010-08-04 13:42:44 +0000804 if (width + xoffset > img->width || height + yoffset > img->height)
805 {
806 error(GL_INVALID_VALUE);
807 return false;
808 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000809
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000810 if (!img->surface)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000811 {
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000812 createSurface(img->width, img->height, format, type, img);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000813 }
814
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000815 if (pixels != NULL && img->surface != NULL)
816 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000817 D3DSURFACE_DESC description;
818 img->surface->GetDesc(&description);
819
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000820 D3DLOCKED_RECT locked;
821 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
822
823 ASSERT(SUCCEEDED(result));
824
825 if (SUCCEEDED(result))
826 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000827 loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000828 img->surface->UnlockRect();
829 }
830
831 img->dirty = true;
832 }
833
daniel@transgaming.com31273552010-08-04 13:42:44 +0000834 return true;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000835}
836
daniel@transgaming.com01868132010-08-24 19:21:17 +0000837bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
838{
839 if (width + xoffset > img->width || height + yoffset > img->height)
840 {
841 error(GL_INVALID_VALUE);
842 return false;
843 }
844
845 if (format != getFormat())
846 {
847 error(GL_INVALID_OPERATION);
848 return false;
849 }
850
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000851 if (!img->surface)
daniel@transgaming.com01868132010-08-24 19:21:17 +0000852 {
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000853 createSurface(img->width, img->height, format, GL_UNSIGNED_BYTE, img);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000854 }
855
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000856 if (pixels != NULL && img->surface != NULL)
857 {
858 RECT updateRegion;
859 updateRegion.left = xoffset;
860 updateRegion.right = xoffset + width;
861 updateRegion.bottom = yoffset + height;
862 updateRegion.top = yoffset;
863
864 D3DLOCKED_RECT locked;
865 HRESULT result = img->surface->LockRect(&locked, &updateRegion, 0);
866
867 ASSERT(SUCCEEDED(result));
868
869 if (SUCCEEDED(result))
870 {
871 GLsizei inputPitch = ComputeCompressedPitch(width, format);
872 int rows = imageSize / inputPitch;
873 for (int i = 0; i < rows; ++i)
874 {
875 memcpy((void*)((BYTE*)locked.pBits + i * locked.Pitch), (void*)((BYTE*)pixels + i * inputPitch), inputPitch);
876 }
877 img->surface->UnlockRect();
878 }
879
880 img->dirty = true;
881 }
882
daniel@transgaming.com01868132010-08-24 19:21:17 +0000883 return true;
884}
885
enne@chromium.org0fa74632010-09-21 16:18:52 +0000886D3DFORMAT Texture::getD3DFormat() const
887{
888 return selectFormat(getFormat(), mType);
889}
890
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000891IDirect3DBaseTexture9 *Texture::getTexture()
892{
893 if (!isComplete())
894 {
895 return NULL;
896 }
897
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000898 if (mDirtyMetaData)
899 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000900 mBaseTexture = createTexture();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000901 mIsRenderable = false;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000902 }
903
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000904 if (mDirtyMetaData || dirtyImageData())
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000905 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000906 updateTexture();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000907 }
908
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000909 mDirtyMetaData = false;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000910 ASSERT(!dirtyImageData());
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000911
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000912 return mBaseTexture;
913}
914
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000915bool Texture::isDirty() const
916{
917 return (mDirty || mDirtyMetaData || dirtyImageData());
918}
919
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000920// Returns the top-level texture surface as a render target
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000921void Texture::needRenderTarget()
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000922{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000923 if (!mIsRenderable)
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000924 {
925 mBaseTexture = convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000926 mIsRenderable = true;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000927 }
928
929 if (dirtyImageData())
930 {
931 updateTexture();
932 }
933
934 mDirtyMetaData = false;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000935}
936
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000937void Texture::dropTexture()
938{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000939 if (mBaseTexture)
940 {
941 mBaseTexture = NULL;
942 }
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000943
944 mIsRenderable = false;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000945}
946
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000947void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000948{
949 mBaseTexture = newTexture;
950 mDirtyMetaData = false;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000951 mIsRenderable = renderable;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000952 mDirty = true;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000953}
954
955
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000956GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
957{
958 if (isPow2(width) && isPow2(height))
959 {
960 return maxlevel;
961 }
962 else
963 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000964 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
965 return 1;
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000966 }
967}
968
969GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
970{
971 return creationLevels(size, size, maxlevel);
972}
973
974int Texture::levelCount() const
975{
976 return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
977}
978
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000979Texture2D::Texture2D(GLuint id) : Texture(id)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000980{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000981 mTexture = NULL;
982}
983
984Texture2D::~Texture2D()
985{
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +0000986 mColorbufferProxy.set(NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000987
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000988 if (mTexture)
989 {
990 mTexture->Release();
991 mTexture = NULL;
992 }
993}
994
995GLenum Texture2D::getTarget() const
996{
997 return GL_TEXTURE_2D;
998}
999
daniel@transgaming.com01868132010-08-24 19:21:17 +00001000GLenum Texture2D::getFormat() const
1001{
1002 return mImageArray[0].format;
1003}
1004
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001005// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1006// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
1007// Call this when a particular level of the texture must be defined with a specific format, width and height.
1008//
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +00001009// 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 +00001010// 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 +00001011bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001012{
1013 bool widthOkay = (mWidth >> level == width);
1014 bool heightOkay = (mHeight >> level == height);
1015
1016 bool sizeOkay = ((widthOkay && heightOkay)
1017 || (widthOkay && mHeight >> level == 0 && height == 1)
1018 || (heightOkay && mWidth >> level == 0 && width == 1));
1019
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001020 bool typeOkay = (type == mType);
1021
1022 bool textureOkay = (sizeOkay && typeOkay && internalFormat == mImageArray[0].format);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001023
1024 if (!textureOkay)
1025 {
1026 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
1027 mImageArray[0].format, mWidth, mHeight,
1028 internalFormat, width, height);
1029
1030 // Purge all the levels and the texture.
1031
daniel@transgaming.com5d752f22010-10-07 13:37:20 +00001032 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001033 {
1034 if (mImageArray[i].surface != NULL)
1035 {
1036 mImageArray[i].dirty = false;
1037
1038 mImageArray[i].surface->Release();
1039 mImageArray[i].surface = NULL;
1040 }
1041 }
1042
1043 if (mTexture != NULL)
1044 {
1045 mTexture->Release();
1046 mTexture = NULL;
1047 dropTexture();
1048 }
1049
1050 mWidth = width << level;
1051 mHeight = height << level;
1052 mImageArray[0].format = internalFormat;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001053 mType = type;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001054 }
1055
1056 return !textureOkay;
1057}
1058
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001059void 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 +00001060{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001061 redefineTexture(level, internalFormat, width, height, type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001062
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001063 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001064}
1065
daniel@transgaming.com01868132010-08-24 19:21:17 +00001066void Texture2D::setCompressedImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1067{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001068 redefineTexture(level, internalFormat, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.com01868132010-08-24 19:21:17 +00001069
1070 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[level]);
1071}
1072
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001073void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1074{
1075 ASSERT(mImageArray[level].surface != NULL);
1076
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001077 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001078 {
1079 IDirect3DSurface9 *destLevel = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001080 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001081
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001082 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001083
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001084 if (SUCCEEDED(result))
1085 {
1086 Image *img = &mImageArray[level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001087
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001088 RECT sourceRect;
1089 sourceRect.left = xoffset;
1090 sourceRect.top = yoffset;
1091 sourceRect.right = xoffset + width;
1092 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001093
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001094 POINT destPoint;
1095 destPoint.x = xoffset;
1096 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001097
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001098 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
1099 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001100
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001101 destLevel->Release();
1102
1103 img->dirty = false;
1104 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001105 }
1106}
1107
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001108void 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 +00001109{
daniel@transgaming.com31273552010-08-04 13:42:44 +00001110 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1111 {
1112 commitRect(level, xoffset, yoffset, width, height);
1113 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001114}
1115
daniel@transgaming.com01868132010-08-24 19:21:17 +00001116void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1117{
1118 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1119 {
1120 commitRect(level, xoffset, yoffset, width, height);
1121 }
1122}
1123
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001124void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001125{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001126 if (redefineTexture(level, internalFormat, width, height, mType))
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001127 {
1128 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001129 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001130 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001131 else
1132 {
1133 needRenderTarget();
1134 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001135
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001136 if (width != 0 && height != 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001137 {
1138 RECT sourceRect;
1139 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001140 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +00001141 sourceRect.top = y;
1142 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001143
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001144 IDirect3DSurface9 *dest;
1145 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001146
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001147 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1148 dest->Release();
1149 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001150
1151 mImageArray[level].width = width;
1152 mImageArray[level].height = height;
1153 mImageArray[level].format = internalFormat;
1154}
1155
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001156void Texture2D::copySubImage(GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001157{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001158 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1159 {
1160 return error(GL_INVALID_VALUE);
1161 }
1162
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001163 if (redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, mType))
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001164 {
1165 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001166 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001167 }
1168 else
1169 {
daniel@transgaming.comfc23fe22010-05-05 18:48:17 +00001170 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001171 }
1172
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001173 if (level < levelCount())
1174 {
1175 RECT sourceRect;
1176 sourceRect.left = x;
1177 sourceRect.right = x + width;
1178 sourceRect.top = y;
1179 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001180
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001181 IDirect3DSurface9 *dest;
1182 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001183
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001184 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
1185 dest->Release();
1186 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001187}
1188
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001189// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1190bool Texture2D::isComplete() const
1191{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001192 GLsizei width = mImageArray[0].width;
1193 GLsizei height = mImageArray[0].height;
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001194
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001195 if (width <= 0 || height <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001196 {
1197 return false;
1198 }
1199
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001200 bool mipmapping = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001201
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001202 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001203 {
1204 case GL_NEAREST:
1205 case GL_LINEAR:
1206 mipmapping = false;
1207 break;
1208 case GL_NEAREST_MIPMAP_NEAREST:
1209 case GL_LINEAR_MIPMAP_NEAREST:
1210 case GL_NEAREST_MIPMAP_LINEAR:
1211 case GL_LINEAR_MIPMAP_LINEAR:
1212 mipmapping = true;
1213 break;
1214 default: UNREACHABLE();
1215 }
1216
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001217 if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1218 (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1219 {
1220 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1221 {
1222 return false;
1223 }
1224 }
1225
1226
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001227 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1228 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1229 {
1230 return false;
1231 }
1232
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001233 if (mipmapping)
1234 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001235 if (!isPow2(width) || !isPow2(height))
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001236 {
1237 return false;
1238 }
1239
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001240 int q = log2(std::max(width, height));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001241
1242 for (int level = 1; level <= q; level++)
1243 {
1244 if (mImageArray[level].format != mImageArray[0].format)
1245 {
1246 return false;
1247 }
1248
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001249 if (mImageArray[level].width != std::max(1, width >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001250 {
1251 return false;
1252 }
1253
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001254 if (mImageArray[level].height != std::max(1, height >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001255 {
1256 return false;
1257 }
1258 }
1259 }
1260
1261 return true;
1262}
1263
daniel@transgaming.com01868132010-08-24 19:21:17 +00001264bool Texture2D::isCompressed() const
1265{
1266 return IsCompressed(getFormat());
1267}
1268
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001269// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001270IDirect3DBaseTexture9 *Texture2D::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001271{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001272 IDirect3DTexture9 *texture;
1273
1274 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001275 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001276
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001277 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001278
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001279 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001280 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001281 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001282 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001283 }
1284
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001285 if (mTexture) mTexture->Release();
1286 mTexture = texture;
1287 return texture;
1288}
1289
1290void Texture2D::updateTexture()
1291{
1292 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001293
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001294 int levels = levelCount();
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001295
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001296 for (int level = 0; level < levels; level++)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001297 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001298 if (mImageArray[level].dirty)
1299 {
1300 IDirect3DSurface9 *levelSurface = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001301 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001302
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001303 ASSERT(SUCCEEDED(result));
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001304
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001305 if (SUCCEEDED(result))
1306 {
1307 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1308 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001309
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001310 levelSurface->Release();
1311
1312 mImageArray[level].dirty = false;
1313 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001314 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001315 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001316}
1317
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001318IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001319{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001320 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001321
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001322 if (mWidth != 0 && mHeight != 0)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001323 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001324 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001325 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001326 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001327
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001328 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 +00001329
1330 if (FAILED(result))
1331 {
1332 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1333 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1334 }
1335
1336 if (mTexture != NULL)
1337 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001338 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001339 for (int i = 0; i < levels; i++)
1340 {
1341 IDirect3DSurface9 *source;
1342 result = mTexture->GetSurfaceLevel(i, &source);
1343
1344 if (FAILED(result))
1345 {
1346 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1347
1348 texture->Release();
1349
1350 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1351 }
1352
1353 IDirect3DSurface9 *dest;
1354 result = texture->GetSurfaceLevel(i, &dest);
1355
1356 if (FAILED(result))
1357 {
1358 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1359
1360 texture->Release();
1361 source->Release();
1362
1363 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1364 }
1365
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001366 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001367 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1368
1369 if (FAILED(result))
1370 {
1371 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1372
1373 texture->Release();
1374 source->Release();
1375 dest->Release();
1376
1377 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1378 }
1379
1380 source->Release();
1381 dest->Release();
1382 }
1383 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001384 }
1385
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001386 if (mTexture != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001387 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001388 mTexture->Release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001389 }
1390
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001391 mTexture = texture;
1392 return mTexture;
1393}
1394
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001395bool Texture2D::dirtyImageData() const
1396{
1397 int q = log2(std::max(mWidth, mHeight));
1398
1399 for (int i = 0; i <= q; i++)
1400 {
1401 if (mImageArray[i].dirty) return true;
1402 }
1403
1404 return false;
1405}
1406
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001407void Texture2D::generateMipmaps()
1408{
1409 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1410 {
1411 return error(GL_INVALID_OPERATION);
1412 }
1413
1414 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1415 unsigned int q = log2(std::max(mWidth, mHeight));
1416 for (unsigned int i = 1; i <= q; i++)
1417 {
1418 if (mImageArray[i].surface != NULL)
1419 {
1420 mImageArray[i].surface->Release();
1421 mImageArray[i].surface = NULL;
1422 }
1423
1424 mImageArray[i].dirty = false;
1425
1426 mImageArray[i].format = mImageArray[0].format;
1427 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1428 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
1429 }
1430
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001431 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001432
apatrick@chromium.org9398a6b2010-09-20 19:07:49 +00001433 if (mTexture == NULL)
1434 {
1435 return;
1436 }
1437
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001438 for (unsigned int i = 1; i <= q; i++)
1439 {
1440 IDirect3DSurface9 *upper = NULL;
1441 IDirect3DSurface9 *lower = NULL;
1442
1443 mTexture->GetSurfaceLevel(i-1, &upper);
1444 mTexture->GetSurfaceLevel(i, &lower);
1445
1446 if (upper != NULL && lower != NULL)
1447 {
1448 getBlitter()->boxFilter(upper, lower);
1449 }
1450
1451 if (upper != NULL) upper->Release();
1452 if (lower != NULL) lower->Release();
1453 }
1454}
1455
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001456Renderbuffer *Texture2D::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001457{
1458 if (target != GL_TEXTURE_2D)
1459 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001460 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001461 }
1462
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001463 if (mColorbufferProxy.get() == NULL)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001464 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001465 mColorbufferProxy.set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001466 }
1467
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001468 return mColorbufferProxy.get();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001469}
1470
1471IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1472{
1473 ASSERT(target == GL_TEXTURE_2D);
1474
1475 needRenderTarget();
1476
apatrick@chromium.org4d5962c2010-09-20 19:02:30 +00001477 if (mTexture == NULL)
1478 {
1479 return NULL;
1480 }
1481
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001482 IDirect3DSurface9 *renderTarget = NULL;
1483 mTexture->GetSurfaceLevel(0, &renderTarget);
1484
1485 return renderTarget;
1486}
1487
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001488TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001489{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001490 mTexture = NULL;
1491}
1492
1493TextureCubeMap::~TextureCubeMap()
1494{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001495 for (int i = 0; i < 6; i++)
1496 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001497 mFaceProxies[i].set(NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001498 }
1499
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001500 if (mTexture)
1501 {
1502 mTexture->Release();
1503 mTexture = NULL;
1504 }
1505}
1506
1507GLenum TextureCubeMap::getTarget() const
1508{
1509 return GL_TEXTURE_CUBE_MAP;
1510}
1511
daniel@transgaming.com01868132010-08-24 19:21:17 +00001512GLenum TextureCubeMap::getFormat() const
1513{
1514 return mImageArray[0][0].format;
1515}
1516
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001517void 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 +00001518{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001519 setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001520}
1521
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001522void 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 +00001523{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001524 setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001525}
1526
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001527void 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 +00001528{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001529 setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001530}
1531
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001532void 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 +00001533{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001534 setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001535}
1536
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001537void 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 +00001538{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001539 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001540}
1541
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001542void 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 +00001543{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001544 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001545}
1546
daniel@transgaming.com01868132010-08-24 19:21:17 +00001547void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1548{
1549 redefineTexture(level, internalFormat, width);
1550
1551 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[faceIndex(face)][level]);
1552}
1553
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001554void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1555{
1556 int face = faceIndex(faceTarget);
1557
1558 ASSERT(mImageArray[face][level].surface != NULL);
1559
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001560 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001561 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001562 IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level);
1563 ASSERT(destLevel != NULL);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001564
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001565 if (destLevel != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001566 {
1567 Image *img = &mImageArray[face][level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001568
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001569 RECT sourceRect;
1570 sourceRect.left = xoffset;
1571 sourceRect.top = yoffset;
1572 sourceRect.right = xoffset + width;
1573 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001574
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001575 POINT destPoint;
1576 destPoint.x = xoffset;
1577 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001578
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001579 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001580 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001581
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001582 destLevel->Release();
1583
1584 img->dirty = false;
1585 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001586 }
1587}
1588
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001589void TextureCubeMap::subImage(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001590{
daniel@transgaming.com31273552010-08-04 13:42:44 +00001591 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(face)][level]))
1592 {
1593 commitRect(face, level, xoffset, yoffset, width, height);
1594 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001595}
1596
daniel@transgaming.com01868132010-08-24 19:21:17 +00001597void TextureCubeMap::subImageCompressed(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1598{
1599 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(face)][level]))
1600 {
1601 commitRect(face, level, xoffset, yoffset, width, height);
1602 }
1603}
1604
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001605// 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 +00001606bool TextureCubeMap::isComplete() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001607{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001608 int size = mImageArray[0][0].width;
1609
1610 if (size <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001611 {
1612 return false;
1613 }
1614
1615 bool mipmapping;
1616
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001617 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001618 {
1619 case GL_NEAREST:
1620 case GL_LINEAR:
1621 mipmapping = false;
1622 break;
1623 case GL_NEAREST_MIPMAP_NEAREST:
1624 case GL_LINEAR_MIPMAP_NEAREST:
1625 case GL_NEAREST_MIPMAP_LINEAR:
1626 case GL_LINEAR_MIPMAP_LINEAR:
1627 mipmapping = true;
1628 break;
1629 default: UNREACHABLE();
1630 }
1631
1632 for (int face = 0; face < 6; face++)
1633 {
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001634 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001635 {
1636 return false;
1637 }
1638 }
1639
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001640 if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1641 (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1642 {
1643 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1644 {
1645 return false;
1646 }
1647 }
1648
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001649 if (mipmapping)
1650 {
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001651 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1652 {
1653 return false;
1654 }
1655
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001656 int q = log2(size);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001657
1658 for (int face = 0; face < 6; face++)
1659 {
1660 for (int level = 1; level <= q; level++)
1661 {
1662 if (mImageArray[face][level].format != mImageArray[0][0].format)
1663 {
1664 return false;
1665 }
1666
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001667 if (mImageArray[face][level].width != std::max(1, size >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001668 {
1669 return false;
1670 }
1671
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001672 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001673 }
1674 }
1675 }
1676
1677 return true;
1678}
1679
daniel@transgaming.com01868132010-08-24 19:21:17 +00001680bool TextureCubeMap::isCompressed() const
1681{
1682 return IsCompressed(getFormat());
1683}
1684
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001685// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001686IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001687{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001688 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001689 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001690
1691 IDirect3DCubeTexture9 *texture;
1692
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001693 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001694
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001695 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001696 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001697 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001698 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001699 }
1700
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001701 if (mTexture) mTexture->Release();
1702
1703 mTexture = texture;
1704 return mTexture;
1705}
1706
1707void TextureCubeMap::updateTexture()
1708{
1709 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001710
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001711 for (int face = 0; face < 6; face++)
1712 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001713 int levels = levelCount();
1714 for (int level = 0; level < levels; level++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001715 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001716 Image *img = &mImageArray[face][level];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001717
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001718 if (img->dirty)
1719 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001720 IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level);
1721 ASSERT(levelSurface != NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001722
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001723 if (levelSurface != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001724 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001725 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001726 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001727
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001728 levelSurface->Release();
1729
1730 img->dirty = false;
1731 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001732 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001733 }
1734 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001735}
1736
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001737IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
1738{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001739 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001740
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001741 if (mWidth != 0)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001742 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001743 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001744 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001745 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001746
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001747 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001748
1749 if (FAILED(result))
1750 {
1751 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1752 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1753 }
1754
1755 if (mTexture != NULL)
1756 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001757 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001758 for (int f = 0; f < 6; f++)
1759 {
1760 for (int i = 0; i < levels; i++)
1761 {
1762 IDirect3DSurface9 *source;
1763 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
1764
1765 if (FAILED(result))
1766 {
1767 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1768
1769 texture->Release();
1770
1771 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1772 }
1773
1774 IDirect3DSurface9 *dest;
1775 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
1776
1777 if (FAILED(result))
1778 {
1779 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1780
1781 texture->Release();
1782 source->Release();
1783
1784 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1785 }
1786
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001787 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001788 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1789
1790 if (FAILED(result))
1791 {
1792 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1793
1794 texture->Release();
1795 source->Release();
1796 dest->Release();
1797
1798 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1799 }
1800 }
1801 }
1802 }
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001803 }
1804
1805 if (mTexture != NULL)
1806 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001807 mTexture->Release();
1808 }
1809
1810 mTexture = texture;
1811 return mTexture;
1812}
1813
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001814void 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 +00001815{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001816 redefineTexture(level, internalFormat, width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001817
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001818 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001819}
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001820
1821unsigned int TextureCubeMap::faceIndex(GLenum face)
1822{
1823 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1824 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1825 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1826 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1827 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1828
1829 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1830}
1831
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001832bool TextureCubeMap::dirtyImageData() const
1833{
1834 int q = log2(mWidth);
1835
1836 for (int f = 0; f < 6; f++)
1837 {
1838 for (int i = 0; i <= q; i++)
1839 {
1840 if (mImageArray[f][i].dirty) return true;
1841 }
1842 }
1843
1844 return false;
1845}
1846
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001847// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1848// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
1849// Call this when a particular level of the texture must be defined with a specific format, width and height.
1850//
1851// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
1852// a new size for the texture by working backwards from the given size.
1853bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
1854{
1855 // Are these settings compatible with level 0?
1856 bool sizeOkay = (mImageArray[0][0].width >> level == width);
1857
1858 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
1859
1860 if (!textureOkay)
1861 {
1862 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
1863 mImageArray[0][0].format, mImageArray[0][0].width,
1864 internalFormat, width);
1865
1866 // Purge all the levels and the texture.
daniel@transgaming.com5d752f22010-10-07 13:37:20 +00001867 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001868 {
1869 for (int f = 0; f < 6; f++)
1870 {
1871 if (mImageArray[f][i].surface != NULL)
1872 {
1873 mImageArray[f][i].dirty = false;
1874
1875 mImageArray[f][i].surface->Release();
1876 mImageArray[f][i].surface = NULL;
1877 }
1878 }
1879 }
1880
1881 if (mTexture != NULL)
1882 {
1883 mTexture->Release();
1884 mTexture = NULL;
1885 dropTexture();
1886 }
1887
1888 mWidth = width << level;
1889 mImageArray[0][0].width = width << level;
1890 mHeight = width << level;
1891 mImageArray[0][0].height = width << level;
1892
1893 mImageArray[0][0].format = internalFormat;
1894 }
1895
1896 return !textureOkay;
1897}
1898
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001899void TextureCubeMap::copyImage(GLenum face, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001900{
1901 unsigned int faceindex = faceIndex(face);
1902
1903 if (redefineTexture(level, internalFormat, width))
1904 {
1905 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001906 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001907 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001908 else
1909 {
1910 needRenderTarget();
1911 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001912
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001913 ASSERT(width == height);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001914
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001915 if (width > 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001916 {
1917 RECT sourceRect;
1918 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001919 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +00001920 sourceRect.top = y;
1921 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001922
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001923 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
1924
1925 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1926 dest->Release();
1927 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001928
1929 mImageArray[faceindex][level].width = width;
1930 mImageArray[faceindex][level].height = height;
1931 mImageArray[faceindex][level].format = internalFormat;
1932}
1933
1934IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(unsigned int faceIdentifier, unsigned int level)
1935{
1936 unsigned int faceIndex;
1937
1938 if (faceIdentifier < 6)
1939 {
1940 faceIndex = faceIdentifier;
1941 }
1942 else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
1943 {
1944 faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1945 }
1946 else
1947 {
1948 UNREACHABLE();
1949 faceIndex = 0;
1950 }
1951
1952 if (mTexture == NULL)
1953 {
1954 UNREACHABLE();
1955 return NULL;
1956 }
1957
1958 IDirect3DSurface9 *surface = NULL;
1959
1960 HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface);
1961
1962 return (SUCCEEDED(hr)) ? surface : NULL;
1963}
1964
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001965void TextureCubeMap::copySubImage(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001966{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001967 GLsizei size = mImageArray[faceIndex(face)][level].width;
1968
1969 if (xoffset + width > size || yoffset + height > size)
1970 {
1971 return error(GL_INVALID_VALUE);
1972 }
1973
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001974 if (redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width))
1975 {
1976 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001977 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001978 }
1979 else
1980 {
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001981 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001982 }
1983
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001984 if (level < levelCount())
1985 {
1986 RECT sourceRect;
1987 sourceRect.left = x;
1988 sourceRect.right = x + width;
1989 sourceRect.top = y;
1990 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001991
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001992 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001993
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001994 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
1995 dest->Release();
1996 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001997}
1998
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001999bool TextureCubeMap::isCubeComplete() const
2000{
2001 if (mImageArray[0][0].width == 0)
2002 {
2003 return false;
2004 }
2005
2006 for (unsigned int f = 1; f < 6; f++)
2007 {
2008 if (mImageArray[f][0].width != mImageArray[0][0].width
2009 || mImageArray[f][0].format != mImageArray[0][0].format)
2010 {
2011 return false;
2012 }
2013 }
2014
2015 return true;
2016}
2017
2018void TextureCubeMap::generateMipmaps()
2019{
2020 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
2021 {
2022 return error(GL_INVALID_OPERATION);
2023 }
2024
2025 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2026 unsigned int q = log2(mImageArray[0][0].width);
2027 for (unsigned int f = 0; f < 6; f++)
2028 {
2029 for (unsigned int i = 1; i <= q; i++)
2030 {
2031 if (mImageArray[f][i].surface != NULL)
2032 {
2033 mImageArray[f][i].surface->Release();
2034 mImageArray[f][i].surface = NULL;
2035 }
2036
2037 mImageArray[f][i].dirty = false;
2038
2039 mImageArray[f][i].format = mImageArray[f][0].format;
2040 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2041 mImageArray[f][i].height = mImageArray[f][i].width;
2042 }
2043 }
2044
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002045 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00002046
apatrick@chromium.org9398a6b2010-09-20 19:07:49 +00002047 if (mTexture == NULL)
2048 {
2049 return;
2050 }
2051
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00002052 for (unsigned int f = 0; f < 6; f++)
2053 {
2054 for (unsigned int i = 1; i <= q; i++)
2055 {
2056 IDirect3DSurface9 *upper = getCubeMapSurface(f, i-1);
2057 IDirect3DSurface9 *lower = getCubeMapSurface(f, i);
2058
2059 if (upper != NULL && lower != NULL)
2060 {
2061 getBlitter()->boxFilter(upper, lower);
2062 }
2063
2064 if (upper != NULL) upper->Release();
2065 if (lower != NULL) lower->Release();
2066 }
2067 }
2068}
2069
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002070Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002071{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002072 if (!IsCubemapTextureTarget(target))
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002073 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002074 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002075 }
2076
2077 unsigned int face = faceIndex(target);
2078
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002079 if (mFaceProxies[face].get() == NULL)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002080 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002081 mFaceProxies[face].set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002082 }
2083
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002084 return mFaceProxies[face].get();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002085}
2086
2087IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2088{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002089 ASSERT(IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002090
2091 needRenderTarget();
daniel@transgaming.come979ead2010-09-23 18:03:14 +00002092
2093 if (mTexture == NULL)
2094 {
2095 return NULL;
apatrick@chromium.org4d5962c2010-09-20 19:02:30 +00002096 }
2097
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002098 IDirect3DSurface9 *renderTarget = NULL;
2099 mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex(target)), 0, &renderTarget);
2100
2101 return renderTarget;
2102}
2103
2104Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
enne@chromium.org0fa74632010-09-21 16:18:52 +00002105 : Colorbuffer(texture), mTexture(texture), mTarget(target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002106{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002107 ASSERT(target == GL_TEXTURE_2D || IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002108}
2109
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002110void Texture::TextureColorbufferProxy::addRef() const
2111{
2112 mTexture->addRef();
2113}
2114
2115void Texture::TextureColorbufferProxy::release() const
2116{
2117 mTexture->release();
2118}
2119
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002120IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
2121{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002122 if (mRenderTarget) mRenderTarget->Release();
2123
2124 mRenderTarget = mTexture->getRenderTarget(mTarget);
2125
2126 return mRenderTarget;
2127}
2128
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002129int Texture::TextureColorbufferProxy::getWidth() const
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002130{
daniel@transgaming.com866f3182010-05-20 19:28:22 +00002131 return mTexture->getWidth();
2132}
2133
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002134int Texture::TextureColorbufferProxy::getHeight() const
daniel@transgaming.com866f3182010-05-20 19:28:22 +00002135{
2136 return mTexture->getHeight();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002137}
2138
daniel@transgaming.com01868132010-08-24 19:21:17 +00002139GLenum Texture::TextureColorbufferProxy::getFormat() const
2140{
2141 return mTexture->getFormat();
2142}
2143
daniel@transgaming.com1297d922010-09-01 15:47:47 +00002144bool Texture::TextureColorbufferProxy::isFloatingPoint() const
2145{
2146 return mTexture->isFloatingPoint();
2147}
2148
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002149}