blob: 226d64cdea4ac98d400f901de0a98d53a813c31a [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.com01868132010-08-24 19:21:17 +0000199 else
200 {
201 return D3DFMT_A8R8G8B8;
202 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000203}
204
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000205// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
206// into the BGRA8 pixel rectangle at output with outputPitch bytes in between each line.
207void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000208 GLint unpackAlignment, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000209{
daniel@transgaming.com713914b2010-05-04 03:35:17 +0000210 GLsizei inputPitch = ComputePitch(width, format, type, unpackAlignment);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000211
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000212 switch (type)
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000213 {
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000214 case GL_UNSIGNED_BYTE:
215 switch (format)
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000216 {
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000217 case GL_ALPHA:
218 loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
219 break;
220 case GL_LUMINANCE:
221 loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
222 break;
223 case GL_LUMINANCE_ALPHA:
224 loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
225 break;
226 case GL_RGB:
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000227 loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
228 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000229 case GL_RGBA:
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000230 loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
231 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000232 case GL_BGRA_EXT:
233 loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000234 break;
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000235 default: UNREACHABLE();
236 }
237 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000238 case GL_UNSIGNED_SHORT_5_6_5:
239 switch (format)
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000240 {
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000241 case GL_RGB:
242 loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000243 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000244 default: UNREACHABLE();
245 }
246 break;
247 case GL_UNSIGNED_SHORT_4_4_4_4:
248 switch (format)
249 {
250 case GL_RGBA:
251 loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
252 break;
253 default: UNREACHABLE();
254 }
255 break;
256 case GL_UNSIGNED_SHORT_5_5_5_1:
257 switch (format)
258 {
259 case GL_RGBA:
260 loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
261 break;
262 default: UNREACHABLE();
263 }
264 break;
265 case GL_FLOAT:
266 switch (format)
267 {
268 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
269 case GL_ALPHA:
270 loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
271 break;
272 case GL_LUMINANCE:
273 loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
274 break;
275 case GL_LUMINANCE_ALPHA:
276 loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
277 break;
278 case GL_RGB:
279 loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
280 break;
281 case GL_RGBA:
282 loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
283 break;
284 default: UNREACHABLE();
285 }
286 break;
287 case GL_HALF_FLOAT_OES:
288 switch (format)
289 {
290 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
291 case GL_ALPHA:
292 loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
293 break;
294 case GL_LUMINANCE:
295 loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
296 break;
297 case GL_LUMINANCE_ALPHA:
298 loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
299 break;
300 case GL_RGB:
301 loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
302 break;
303 case GL_RGBA:
304 loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
305 break;
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000306 default: UNREACHABLE();
307 }
308 break;
309 default: UNREACHABLE();
310 }
311}
312
313void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
314 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
315{
316 const unsigned char *source = NULL;
317 unsigned char *dest = NULL;
318
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000319 for (int y = 0; y < height; y++)
320 {
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000321 source = static_cast<const unsigned char*>(input) + y * inputPitch;
322 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000323 for (int x = 0; x < width; x++)
324 {
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000325 dest[4 * x + 0] = 0;
326 dest[4 * x + 1] = 0;
327 dest[4 * x + 2] = 0;
328 dest[4 * x + 3] = source[x];
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000329 }
330 }
331}
332
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000333void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
334 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
335{
336 const float *source = NULL;
337 float *dest = NULL;
338
339 for (int y = 0; y < height; y++)
340 {
341 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
342 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
343 for (int x = 0; x < width; x++)
344 {
345 dest[4 * x + 0] = 0;
346 dest[4 * x + 1] = 0;
347 dest[4 * x + 2] = 0;
348 dest[4 * x + 3] = source[x];
349 }
350 }
351}
352
353void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
354 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
355{
356 const unsigned short *source = NULL;
357 unsigned short *dest = NULL;
358
359 for (int y = 0; y < height; y++)
360 {
361 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
362 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
363 for (int x = 0; x < width; x++)
364 {
365 dest[4 * x + 0] = 0;
366 dest[4 * x + 1] = 0;
367 dest[4 * x + 2] = 0;
368 dest[4 * x + 3] = source[x];
369 }
370 }
371}
372
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000373void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
374 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
375{
376 const unsigned char *source = NULL;
377 unsigned char *dest = NULL;
378
379 for (int y = 0; y < height; y++)
380 {
381 source = static_cast<const unsigned char*>(input) + y * inputPitch;
382 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
383 for (int x = 0; x < width; x++)
384 {
385 dest[4 * x + 0] = source[x];
386 dest[4 * x + 1] = source[x];
387 dest[4 * x + 2] = source[x];
388 dest[4 * x + 3] = 0xFF;
389 }
390 }
391}
392
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000393void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
394 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
395{
396 const float *source = NULL;
397 float *dest = NULL;
398
399 for (int y = 0; y < height; y++)
400 {
401 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
402 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
403 for (int x = 0; x < width; x++)
404 {
405 dest[4 * x + 0] = source[x];
406 dest[4 * x + 1] = source[x];
407 dest[4 * x + 2] = source[x];
408 dest[4 * x + 3] = 1.0f;
409 }
410 }
411}
412
413void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
414 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
415{
416 const unsigned short *source = NULL;
417 unsigned short *dest = NULL;
418
419 for (int y = 0; y < height; y++)
420 {
421 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
422 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
423 for (int x = 0; x < width; x++)
424 {
425 dest[4 * x + 0] = source[x];
426 dest[4 * x + 1] = source[x];
427 dest[4 * x + 2] = source[x];
428 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
429 }
430 }
431}
432
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000433void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
434 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
435{
436 const unsigned char *source = NULL;
437 unsigned char *dest = NULL;
438
439 for (int y = 0; y < height; y++)
440 {
441 source = static_cast<const unsigned char*>(input) + y * inputPitch;
442 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
443 for (int x = 0; x < width; x++)
444 {
445 dest[4 * x + 0] = source[2*x+0];
446 dest[4 * x + 1] = source[2*x+0];
447 dest[4 * x + 2] = source[2*x+0];
448 dest[4 * x + 3] = source[2*x+1];
449 }
450 }
451}
452
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000453void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
454 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
455{
456 const float *source = NULL;
457 float *dest = NULL;
458
459 for (int y = 0; y < height; y++)
460 {
461 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
462 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
463 for (int x = 0; x < width; x++)
464 {
465 dest[4 * x + 0] = source[2*x+0];
466 dest[4 * x + 1] = source[2*x+0];
467 dest[4 * x + 2] = source[2*x+0];
468 dest[4 * x + 3] = source[2*x+1];
469 }
470 }
471}
472
473void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
474 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
475{
476 const unsigned short *source = NULL;
477 unsigned short *dest = NULL;
478
479 for (int y = 0; y < height; y++)
480 {
481 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
482 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
483 for (int x = 0; x < width; x++)
484 {
485 dest[4 * x + 0] = source[2*x+0];
486 dest[4 * x + 1] = source[2*x+0];
487 dest[4 * x + 2] = source[2*x+0];
488 dest[4 * x + 3] = source[2*x+1];
489 }
490 }
491}
492
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000493void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
494 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
495{
496 const unsigned char *source = NULL;
497 unsigned char *dest = NULL;
498
499 for (int y = 0; y < height; y++)
500 {
501 source = static_cast<const unsigned char*>(input) + y * inputPitch;
502 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
503 for (int x = 0; x < width; x++)
504 {
505 dest[4 * x + 0] = source[x * 3 + 2];
506 dest[4 * x + 1] = source[x * 3 + 1];
507 dest[4 * x + 2] = source[x * 3 + 0];
508 dest[4 * x + 3] = 0xFF;
509 }
510 }
511}
512
513void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
514 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
515{
516 const unsigned short *source = NULL;
517 unsigned char *dest = NULL;
518
519 for (int y = 0; y < height; y++)
520 {
521 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
522 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
523 for (int x = 0; x < width; x++)
524 {
525 unsigned short rgba = source[x];
526 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
527 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
528 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
529 dest[4 * x + 3] = 0xFF;
530 }
531 }
532}
533
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000534void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
535 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
536{
537 const float *source = NULL;
538 float *dest = NULL;
539
540 for (int y = 0; y < height; y++)
541 {
542 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
543 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
544 for (int x = 0; x < width; x++)
545 {
546 dest[4 * x + 0] = source[x * 3 + 0];
547 dest[4 * x + 1] = source[x * 3 + 1];
548 dest[4 * x + 2] = source[x * 3 + 2];
549 dest[4 * x + 3] = 1.0f;
550 }
551 }
552}
553
554void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
555 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
556{
557 const unsigned short *source = NULL;
558 unsigned short *dest = NULL;
559
560 for (int y = 0; y < height; y++)
561 {
562 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
563 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
564 for (int x = 0; x < width; x++)
565 {
566 dest[4 * x + 0] = source[x * 3 + 0];
567 dest[4 * x + 1] = source[x * 3 + 1];
568 dest[4 * x + 2] = source[x * 3 + 2];
569 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
570 }
571 }
572}
573
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000574void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
575 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
576{
577 const unsigned char *source = NULL;
578 unsigned char *dest = NULL;
579
580 for (int y = 0; y < height; y++)
581 {
582 source = static_cast<const unsigned char*>(input) + y * inputPitch;
583 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
584 for (int x = 0; x < width; x++)
585 {
586 dest[4 * x + 0] = source[x * 4 + 2];
587 dest[4 * x + 1] = source[x * 4 + 1];
588 dest[4 * x + 2] = source[x * 4 + 0];
589 dest[4 * x + 3] = source[x * 4 + 3];
590 }
591 }
592}
593
594void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
595 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
596{
597 const unsigned short *source = NULL;
598 unsigned char *dest = NULL;
599
600 for (int y = 0; y < height; y++)
601 {
602 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
603 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
604 for (int x = 0; x < width; x++)
605 {
606 unsigned short rgba = source[x];
607 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
608 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
609 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
610 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
611 }
612 }
613}
614
615void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
616 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
617{
618 const unsigned short *source = NULL;
619 unsigned char *dest = NULL;
620
621 for (int y = 0; y < height; y++)
622 {
623 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
624 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
625 for (int x = 0; x < width; x++)
626 {
627 unsigned short rgba = source[x];
628 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
629 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
630 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
631 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
632 }
633 }
634}
635
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000636void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
637 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
638{
639 const float *source = NULL;
640 float *dest = NULL;
641
642 for (int y = 0; y < height; y++)
643 {
644 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
645 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
646 memcpy(dest, source, width * 16);
647 }
648}
649
650void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
651 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
652{
653 const unsigned char *source = NULL;
654 unsigned char *dest = NULL;
655
656 for (int y = 0; y < height; y++)
657 {
658 source = static_cast<const unsigned char*>(input) + y * inputPitch;
659 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
660 memcpy(dest, source, width * 8);
661 }
662}
663
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000664void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
665 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
666{
667 const unsigned char *source = NULL;
668 unsigned char *dest = NULL;
669
670 for (int y = 0; y < height; y++)
671 {
672 source = static_cast<const unsigned char*>(input) + y * inputPitch;
673 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
674 memcpy(dest, source, width*4);
675 }
676}
677
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000678void Texture::createSurface(GLsizei width, GLsizei height, GLenum format, GLenum type, Image *img)
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000679{
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000680 IDirect3DTexture9 *newTexture = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000681 IDirect3DSurface9 *newSurface = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000682
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000683 if (width != 0 && height != 0)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000684 {
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000685 int levelToFetch = 0;
686 GLsizei requestWidth = width;
687 GLsizei requestHeight = height;
688 if (IsCompressed(format) && (width % 4 != 0 || height % 4 != 0))
689 {
690 bool isMult4 = false;
691 int upsampleCount = 0;
692 while (!isMult4)
693 {
694 requestWidth <<= 1;
695 requestHeight <<= 1;
696 upsampleCount++;
697 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
698 {
699 isMult4 = true;
700 }
701 }
702 levelToFetch = upsampleCount;
703 }
704
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000705 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, selectFormat(format, type),
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000706 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000707
708 if (FAILED(result))
709 {
710 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
711 return error(GL_OUT_OF_MEMORY);
712 }
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000713
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000714 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000715 newTexture->Release();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000716 }
717
718 if (img->surface) img->surface->Release();
719 img->surface = newSurface;
720
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000721 img->width = width;
722 img->height = height;
723 img->format = format;
daniel@transgaming.com01868132010-08-24 19:21:17 +0000724}
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000725
daniel@transgaming.com01868132010-08-24 19:21:17 +0000726void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
727{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000728 createSurface(width, height, format, type, img);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000729
730 if (pixels != NULL && img->surface != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000731 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000732 D3DLOCKED_RECT locked;
daniel@transgaming.com01868132010-08-24 19:21:17 +0000733 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000734
735 ASSERT(SUCCEEDED(result));
736
737 if (SUCCEEDED(result))
738 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000739 loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000740 img->surface->UnlockRect();
741 }
742
743 img->dirty = true;
744 }
745
746 mDirtyMetaData = true;
747}
748
749void Texture::setCompressedImage(GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
750{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000751 createSurface(width, height, format, GL_UNSIGNED_BYTE, img);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000752
753 if (pixels != NULL && img->surface != NULL)
754 {
755 D3DLOCKED_RECT locked;
756 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
757
758 ASSERT(SUCCEEDED(result));
759
760 if (SUCCEEDED(result))
761 {
762 memcpy(locked.pBits, pixels, imageSize);
763 img->surface->UnlockRect();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000764 }
765
766 img->dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000767 }
768
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000769 mDirtyMetaData = true;
770}
771
daniel@transgaming.com31273552010-08-04 13:42:44 +0000772bool 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 +0000773{
daniel@transgaming.com31273552010-08-04 13:42:44 +0000774 if (width + xoffset > img->width || height + yoffset > img->height)
775 {
776 error(GL_INVALID_VALUE);
777 return false;
778 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000779
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000780 D3DLOCKED_RECT locked;
781 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000782
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000783 ASSERT(SUCCEEDED(result));
784
785 if (SUCCEEDED(result))
786 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000787 loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000788 img->surface->UnlockRect();
789 }
790
791 img->dirty = true;
daniel@transgaming.com31273552010-08-04 13:42:44 +0000792 return true;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000793}
794
daniel@transgaming.com01868132010-08-24 19:21:17 +0000795bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
796{
797 if (width + xoffset > img->width || height + yoffset > img->height)
798 {
799 error(GL_INVALID_VALUE);
800 return false;
801 }
802
803 if (format != getFormat())
804 {
805 error(GL_INVALID_OPERATION);
806 return false;
807 }
808
809 RECT updateRegion;
810 updateRegion.left = xoffset;
811 updateRegion.right = xoffset + width;
812 updateRegion.bottom = yoffset + height;
813 updateRegion.top = yoffset;
814
815 D3DLOCKED_RECT locked;
816 HRESULT result = img->surface->LockRect(&locked, &updateRegion, 0);
817
818 ASSERT(SUCCEEDED(result));
819
820 if (SUCCEEDED(result))
821 {
822 GLsizei inputPitch = ComputeCompressedPitch(width, format);
823 int rows = imageSize / inputPitch;
824 for (int i = 0; i < rows; ++i)
825 {
826 memcpy((void*)((BYTE*)locked.pBits + i * locked.Pitch), (void*)((BYTE*)pixels + i * inputPitch), inputPitch);
827 }
828 img->surface->UnlockRect();
829 }
830
831 img->dirty = true;
832 return true;
833}
834
enne@chromium.org0fa74632010-09-21 16:18:52 +0000835D3DFORMAT Texture::getD3DFormat() const
836{
837 return selectFormat(getFormat(), mType);
838}
839
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000840IDirect3DBaseTexture9 *Texture::getTexture()
841{
842 if (!isComplete())
843 {
844 return NULL;
845 }
846
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000847 if (mDirtyMetaData)
848 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000849 mBaseTexture = createTexture();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000850 mIsRenderable = false;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000851 }
852
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000853 if (mDirtyMetaData || dirtyImageData())
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000854 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000855 updateTexture();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000856 }
857
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000858 mDirtyMetaData = false;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000859 ASSERT(!dirtyImageData());
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000860
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000861 return mBaseTexture;
862}
863
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000864bool Texture::isDirty() const
865{
866 return (mDirty || mDirtyMetaData || dirtyImageData());
867}
868
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000869// Returns the top-level texture surface as a render target
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000870void Texture::needRenderTarget()
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000871{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000872 if (!mIsRenderable)
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000873 {
874 mBaseTexture = convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000875 mIsRenderable = true;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000876 }
877
878 if (dirtyImageData())
879 {
880 updateTexture();
881 }
882
883 mDirtyMetaData = false;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000884}
885
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000886void Texture::dropTexture()
887{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000888 if (mBaseTexture)
889 {
890 mBaseTexture = NULL;
891 }
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000892
893 mIsRenderable = false;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000894}
895
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000896void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000897{
898 mBaseTexture = newTexture;
899 mDirtyMetaData = false;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000900 mIsRenderable = renderable;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000901 mDirty = true;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000902}
903
904
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000905GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
906{
907 if (isPow2(width) && isPow2(height))
908 {
909 return maxlevel;
910 }
911 else
912 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000913 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
914 return 1;
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000915 }
916}
917
918GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
919{
920 return creationLevels(size, size, maxlevel);
921}
922
923int Texture::levelCount() const
924{
925 return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
926}
927
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000928Texture2D::Texture2D(GLuint id) : Texture(id)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000929{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000930 mTexture = NULL;
931}
932
933Texture2D::~Texture2D()
934{
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +0000935 mColorbufferProxy.set(NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000936
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000937 if (mTexture)
938 {
939 mTexture->Release();
940 mTexture = NULL;
941 }
942}
943
944GLenum Texture2D::getTarget() const
945{
946 return GL_TEXTURE_2D;
947}
948
daniel@transgaming.com01868132010-08-24 19:21:17 +0000949GLenum Texture2D::getFormat() const
950{
951 return mImageArray[0].format;
952}
953
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000954// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
955// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
956// Call this when a particular level of the texture must be defined with a specific format, width and height.
957//
958// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
959// 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 +0000960bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000961{
962 bool widthOkay = (mWidth >> level == width);
963 bool heightOkay = (mHeight >> level == height);
964
965 bool sizeOkay = ((widthOkay && heightOkay)
966 || (widthOkay && mHeight >> level == 0 && height == 1)
967 || (heightOkay && mWidth >> level == 0 && width == 1));
968
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000969 bool typeOkay = (type == mType);
970
971 bool textureOkay = (sizeOkay && typeOkay && internalFormat == mImageArray[0].format);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000972
973 if (!textureOkay)
974 {
975 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
976 mImageArray[0].format, mWidth, mHeight,
977 internalFormat, width, height);
978
979 // Purge all the levels and the texture.
980
981 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
982 {
983 if (mImageArray[i].surface != NULL)
984 {
985 mImageArray[i].dirty = false;
986
987 mImageArray[i].surface->Release();
988 mImageArray[i].surface = NULL;
989 }
990 }
991
992 if (mTexture != NULL)
993 {
994 mTexture->Release();
995 mTexture = NULL;
996 dropTexture();
997 }
998
999 mWidth = width << level;
1000 mHeight = height << level;
1001 mImageArray[0].format = internalFormat;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001002 mType = type;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001003 }
1004
1005 return !textureOkay;
1006}
1007
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001008void 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 +00001009{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001010 redefineTexture(level, internalFormat, width, height, type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001011
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001012 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001013}
1014
daniel@transgaming.com01868132010-08-24 19:21:17 +00001015void Texture2D::setCompressedImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1016{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001017 redefineTexture(level, internalFormat, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.com01868132010-08-24 19:21:17 +00001018
1019 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[level]);
1020}
1021
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001022void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1023{
1024 ASSERT(mImageArray[level].surface != NULL);
1025
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001026 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001027 {
1028 IDirect3DSurface9 *destLevel = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001029 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001030
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001031 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001032
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001033 if (SUCCEEDED(result))
1034 {
1035 Image *img = &mImageArray[level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001036
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001037 RECT sourceRect;
1038 sourceRect.left = xoffset;
1039 sourceRect.top = yoffset;
1040 sourceRect.right = xoffset + width;
1041 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001042
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001043 POINT destPoint;
1044 destPoint.x = xoffset;
1045 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001046
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001047 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
1048 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001049
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001050 destLevel->Release();
1051
1052 img->dirty = false;
1053 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001054 }
1055}
1056
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001057void 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 +00001058{
daniel@transgaming.com31273552010-08-04 13:42:44 +00001059 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1060 {
1061 commitRect(level, xoffset, yoffset, width, height);
1062 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001063}
1064
daniel@transgaming.com01868132010-08-24 19:21:17 +00001065void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1066{
1067 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1068 {
1069 commitRect(level, xoffset, yoffset, width, height);
1070 }
1071}
1072
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001073void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001074{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001075 if (redefineTexture(level, internalFormat, width, height, mType))
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001076 {
1077 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001078 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001079 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001080 else
1081 {
1082 needRenderTarget();
1083 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001084
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001085 if (width != 0 && height != 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001086 {
1087 RECT sourceRect;
1088 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001089 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +00001090 sourceRect.top = y;
1091 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001092
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001093 IDirect3DSurface9 *dest;
1094 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001095
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001096 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1097 dest->Release();
1098 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001099
1100 mImageArray[level].width = width;
1101 mImageArray[level].height = height;
1102 mImageArray[level].format = internalFormat;
1103}
1104
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001105void 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 +00001106{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001107 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1108 {
1109 return error(GL_INVALID_VALUE);
1110 }
1111
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001112 if (redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, mType))
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001113 {
1114 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001115 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001116 }
1117 else
1118 {
daniel@transgaming.comfc23fe22010-05-05 18:48:17 +00001119 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001120 }
1121
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001122 if (level < levelCount())
1123 {
1124 RECT sourceRect;
1125 sourceRect.left = x;
1126 sourceRect.right = x + width;
1127 sourceRect.top = y;
1128 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001129
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001130 IDirect3DSurface9 *dest;
1131 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001132
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001133 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
1134 dest->Release();
1135 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001136}
1137
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001138// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1139bool Texture2D::isComplete() const
1140{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001141 GLsizei width = mImageArray[0].width;
1142 GLsizei height = mImageArray[0].height;
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001143
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001144 if (width <= 0 || height <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001145 {
1146 return false;
1147 }
1148
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001149 bool mipmapping = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001150
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001151 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001152 {
1153 case GL_NEAREST:
1154 case GL_LINEAR:
1155 mipmapping = false;
1156 break;
1157 case GL_NEAREST_MIPMAP_NEAREST:
1158 case GL_LINEAR_MIPMAP_NEAREST:
1159 case GL_NEAREST_MIPMAP_LINEAR:
1160 case GL_LINEAR_MIPMAP_LINEAR:
1161 mipmapping = true;
1162 break;
1163 default: UNREACHABLE();
1164 }
1165
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001166 if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1167 (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1168 {
1169 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1170 {
1171 return false;
1172 }
1173 }
1174
1175
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001176 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1177 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1178 {
1179 return false;
1180 }
1181
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001182 if (mipmapping)
1183 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001184 if (!isPow2(width) || !isPow2(height))
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001185 {
1186 return false;
1187 }
1188
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001189 int q = log2(std::max(width, height));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001190
1191 for (int level = 1; level <= q; level++)
1192 {
1193 if (mImageArray[level].format != mImageArray[0].format)
1194 {
1195 return false;
1196 }
1197
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001198 if (mImageArray[level].width != std::max(1, width >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001199 {
1200 return false;
1201 }
1202
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001203 if (mImageArray[level].height != std::max(1, height >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001204 {
1205 return false;
1206 }
1207 }
1208 }
1209
1210 return true;
1211}
1212
daniel@transgaming.com01868132010-08-24 19:21:17 +00001213bool Texture2D::isCompressed() const
1214{
1215 return IsCompressed(getFormat());
1216}
1217
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001218// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001219IDirect3DBaseTexture9 *Texture2D::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001220{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001221 IDirect3DTexture9 *texture;
1222
1223 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001224 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001225
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001226 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001227
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001228 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001229 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001230 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001231 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001232 }
1233
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001234 if (mTexture) mTexture->Release();
1235 mTexture = texture;
1236 return texture;
1237}
1238
1239void Texture2D::updateTexture()
1240{
1241 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001242
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001243 int levels = levelCount();
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001244
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001245 for (int level = 0; level < levels; level++)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001246 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001247 if (mImageArray[level].dirty)
1248 {
1249 IDirect3DSurface9 *levelSurface = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001250 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001251
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001252 ASSERT(SUCCEEDED(result));
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001253
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001254 if (SUCCEEDED(result))
1255 {
1256 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1257 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001258
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001259 levelSurface->Release();
1260
1261 mImageArray[level].dirty = false;
1262 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001263 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001264 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001265}
1266
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001267IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001268{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001269 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001270
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001271 if (mWidth != 0 && mHeight != 0)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001272 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001273 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001274 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001275 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001276
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001277 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 +00001278
1279 if (FAILED(result))
1280 {
1281 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1282 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1283 }
1284
1285 if (mTexture != NULL)
1286 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001287 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001288 for (int i = 0; i < levels; i++)
1289 {
1290 IDirect3DSurface9 *source;
1291 result = mTexture->GetSurfaceLevel(i, &source);
1292
1293 if (FAILED(result))
1294 {
1295 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1296
1297 texture->Release();
1298
1299 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1300 }
1301
1302 IDirect3DSurface9 *dest;
1303 result = texture->GetSurfaceLevel(i, &dest);
1304
1305 if (FAILED(result))
1306 {
1307 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1308
1309 texture->Release();
1310 source->Release();
1311
1312 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1313 }
1314
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001315 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001316 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1317
1318 if (FAILED(result))
1319 {
1320 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1321
1322 texture->Release();
1323 source->Release();
1324 dest->Release();
1325
1326 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1327 }
1328
1329 source->Release();
1330 dest->Release();
1331 }
1332 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001333 }
1334
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001335 if (mTexture != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001336 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001337 mTexture->Release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001338 }
1339
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001340 mTexture = texture;
1341 return mTexture;
1342}
1343
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001344bool Texture2D::dirtyImageData() const
1345{
1346 int q = log2(std::max(mWidth, mHeight));
1347
1348 for (int i = 0; i <= q; i++)
1349 {
1350 if (mImageArray[i].dirty) return true;
1351 }
1352
1353 return false;
1354}
1355
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001356void Texture2D::generateMipmaps()
1357{
1358 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1359 {
1360 return error(GL_INVALID_OPERATION);
1361 }
1362
1363 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1364 unsigned int q = log2(std::max(mWidth, mHeight));
1365 for (unsigned int i = 1; i <= q; i++)
1366 {
1367 if (mImageArray[i].surface != NULL)
1368 {
1369 mImageArray[i].surface->Release();
1370 mImageArray[i].surface = NULL;
1371 }
1372
1373 mImageArray[i].dirty = false;
1374
1375 mImageArray[i].format = mImageArray[0].format;
1376 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1377 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
1378 }
1379
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001380 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001381
apatrick@chromium.org9398a6b2010-09-20 19:07:49 +00001382 if (mTexture == NULL)
1383 {
1384 return;
1385 }
1386
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001387 for (unsigned int i = 1; i <= q; i++)
1388 {
1389 IDirect3DSurface9 *upper = NULL;
1390 IDirect3DSurface9 *lower = NULL;
1391
1392 mTexture->GetSurfaceLevel(i-1, &upper);
1393 mTexture->GetSurfaceLevel(i, &lower);
1394
1395 if (upper != NULL && lower != NULL)
1396 {
1397 getBlitter()->boxFilter(upper, lower);
1398 }
1399
1400 if (upper != NULL) upper->Release();
1401 if (lower != NULL) lower->Release();
1402 }
1403}
1404
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001405Renderbuffer *Texture2D::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001406{
1407 if (target != GL_TEXTURE_2D)
1408 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001409 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001410 }
1411
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001412 if (mColorbufferProxy.get() == NULL)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001413 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001414 mColorbufferProxy.set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001415 }
1416
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001417 return mColorbufferProxy.get();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001418}
1419
1420IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1421{
1422 ASSERT(target == GL_TEXTURE_2D);
1423
1424 needRenderTarget();
1425
apatrick@chromium.org4d5962c2010-09-20 19:02:30 +00001426 if (mTexture == NULL)
1427 {
1428 return NULL;
1429 }
1430
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001431 IDirect3DSurface9 *renderTarget = NULL;
1432 mTexture->GetSurfaceLevel(0, &renderTarget);
1433
1434 return renderTarget;
1435}
1436
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001437TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001438{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001439 mTexture = NULL;
1440}
1441
1442TextureCubeMap::~TextureCubeMap()
1443{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001444 for (int i = 0; i < 6; i++)
1445 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001446 mFaceProxies[i].set(NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001447 }
1448
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001449 if (mTexture)
1450 {
1451 mTexture->Release();
1452 mTexture = NULL;
1453 }
1454}
1455
1456GLenum TextureCubeMap::getTarget() const
1457{
1458 return GL_TEXTURE_CUBE_MAP;
1459}
1460
daniel@transgaming.com01868132010-08-24 19:21:17 +00001461GLenum TextureCubeMap::getFormat() const
1462{
1463 return mImageArray[0][0].format;
1464}
1465
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001466void 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 +00001467{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001468 setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001469}
1470
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001471void 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 +00001472{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001473 setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001474}
1475
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001476void 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 +00001477{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001478 setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001479}
1480
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001481void 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 +00001482{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001483 setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001484}
1485
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001486void 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 +00001487{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001488 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001489}
1490
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001491void 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 +00001492{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001493 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001494}
1495
daniel@transgaming.com01868132010-08-24 19:21:17 +00001496void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1497{
1498 redefineTexture(level, internalFormat, width);
1499
1500 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[faceIndex(face)][level]);
1501}
1502
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001503void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1504{
1505 int face = faceIndex(faceTarget);
1506
1507 ASSERT(mImageArray[face][level].surface != NULL);
1508
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001509 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001510 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001511 IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level);
1512 ASSERT(destLevel != NULL);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001513
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001514 if (destLevel != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001515 {
1516 Image *img = &mImageArray[face][level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001517
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001518 RECT sourceRect;
1519 sourceRect.left = xoffset;
1520 sourceRect.top = yoffset;
1521 sourceRect.right = xoffset + width;
1522 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001523
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001524 POINT destPoint;
1525 destPoint.x = xoffset;
1526 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001527
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001528 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001529 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001530
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001531 destLevel->Release();
1532
1533 img->dirty = false;
1534 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001535 }
1536}
1537
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001538void 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 +00001539{
daniel@transgaming.com31273552010-08-04 13:42:44 +00001540 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(face)][level]))
1541 {
1542 commitRect(face, level, xoffset, yoffset, width, height);
1543 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001544}
1545
daniel@transgaming.com01868132010-08-24 19:21:17 +00001546void TextureCubeMap::subImageCompressed(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1547{
1548 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(face)][level]))
1549 {
1550 commitRect(face, level, xoffset, yoffset, width, height);
1551 }
1552}
1553
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001554// 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 +00001555bool TextureCubeMap::isComplete() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001556{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001557 int size = mImageArray[0][0].width;
1558
1559 if (size <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001560 {
1561 return false;
1562 }
1563
1564 bool mipmapping;
1565
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001566 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001567 {
1568 case GL_NEAREST:
1569 case GL_LINEAR:
1570 mipmapping = false;
1571 break;
1572 case GL_NEAREST_MIPMAP_NEAREST:
1573 case GL_LINEAR_MIPMAP_NEAREST:
1574 case GL_NEAREST_MIPMAP_LINEAR:
1575 case GL_LINEAR_MIPMAP_LINEAR:
1576 mipmapping = true;
1577 break;
1578 default: UNREACHABLE();
1579 }
1580
1581 for (int face = 0; face < 6; face++)
1582 {
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001583 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001584 {
1585 return false;
1586 }
1587 }
1588
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001589 if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1590 (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1591 {
1592 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1593 {
1594 return false;
1595 }
1596 }
1597
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001598 if (mipmapping)
1599 {
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001600 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1601 {
1602 return false;
1603 }
1604
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001605 int q = log2(size);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001606
1607 for (int face = 0; face < 6; face++)
1608 {
1609 for (int level = 1; level <= q; level++)
1610 {
1611 if (mImageArray[face][level].format != mImageArray[0][0].format)
1612 {
1613 return false;
1614 }
1615
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001616 if (mImageArray[face][level].width != std::max(1, size >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001617 {
1618 return false;
1619 }
1620
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001621 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001622 }
1623 }
1624 }
1625
1626 return true;
1627}
1628
daniel@transgaming.com01868132010-08-24 19:21:17 +00001629bool TextureCubeMap::isCompressed() const
1630{
1631 return IsCompressed(getFormat());
1632}
1633
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001634// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001635IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001636{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001637 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001638 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001639
1640 IDirect3DCubeTexture9 *texture;
1641
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001642 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001643
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001644 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001645 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001646 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001647 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001648 }
1649
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001650 if (mTexture) mTexture->Release();
1651
1652 mTexture = texture;
1653 return mTexture;
1654}
1655
1656void TextureCubeMap::updateTexture()
1657{
1658 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001659
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001660 for (int face = 0; face < 6; face++)
1661 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001662 int levels = levelCount();
1663 for (int level = 0; level < levels; level++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001664 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001665 Image *img = &mImageArray[face][level];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001666
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001667 if (img->dirty)
1668 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001669 IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level);
1670 ASSERT(levelSurface != NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001671
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001672 if (levelSurface != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001673 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001674 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001675 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001676
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001677 levelSurface->Release();
1678
1679 img->dirty = false;
1680 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001681 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001682 }
1683 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001684}
1685
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001686IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
1687{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001688 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001689
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001690 if (mWidth != 0)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001691 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001692 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001693 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001694 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001695
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001696 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001697
1698 if (FAILED(result))
1699 {
1700 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1701 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1702 }
1703
1704 if (mTexture != NULL)
1705 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001706 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001707 for (int f = 0; f < 6; f++)
1708 {
1709 for (int i = 0; i < levels; i++)
1710 {
1711 IDirect3DSurface9 *source;
1712 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
1713
1714 if (FAILED(result))
1715 {
1716 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1717
1718 texture->Release();
1719
1720 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1721 }
1722
1723 IDirect3DSurface9 *dest;
1724 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
1725
1726 if (FAILED(result))
1727 {
1728 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1729
1730 texture->Release();
1731 source->Release();
1732
1733 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1734 }
1735
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001736 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001737 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1738
1739 if (FAILED(result))
1740 {
1741 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1742
1743 texture->Release();
1744 source->Release();
1745 dest->Release();
1746
1747 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1748 }
1749 }
1750 }
1751 }
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001752 }
1753
1754 if (mTexture != NULL)
1755 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001756 mTexture->Release();
1757 }
1758
1759 mTexture = texture;
1760 return mTexture;
1761}
1762
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001763void 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 +00001764{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001765 redefineTexture(level, internalFormat, width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001766
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001767 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001768}
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001769
1770unsigned int TextureCubeMap::faceIndex(GLenum face)
1771{
1772 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1773 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1774 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1775 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1776 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1777
1778 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1779}
1780
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001781bool TextureCubeMap::dirtyImageData() const
1782{
1783 int q = log2(mWidth);
1784
1785 for (int f = 0; f < 6; f++)
1786 {
1787 for (int i = 0; i <= q; i++)
1788 {
1789 if (mImageArray[f][i].dirty) return true;
1790 }
1791 }
1792
1793 return false;
1794}
1795
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001796// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1797// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
1798// Call this when a particular level of the texture must be defined with a specific format, width and height.
1799//
1800// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
1801// a new size for the texture by working backwards from the given size.
1802bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
1803{
1804 // Are these settings compatible with level 0?
1805 bool sizeOkay = (mImageArray[0][0].width >> level == width);
1806
1807 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
1808
1809 if (!textureOkay)
1810 {
1811 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
1812 mImageArray[0][0].format, mImageArray[0][0].width,
1813 internalFormat, width);
1814
1815 // Purge all the levels and the texture.
1816 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
1817 {
1818 for (int f = 0; f < 6; f++)
1819 {
1820 if (mImageArray[f][i].surface != NULL)
1821 {
1822 mImageArray[f][i].dirty = false;
1823
1824 mImageArray[f][i].surface->Release();
1825 mImageArray[f][i].surface = NULL;
1826 }
1827 }
1828 }
1829
1830 if (mTexture != NULL)
1831 {
1832 mTexture->Release();
1833 mTexture = NULL;
1834 dropTexture();
1835 }
1836
1837 mWidth = width << level;
1838 mImageArray[0][0].width = width << level;
1839 mHeight = width << level;
1840 mImageArray[0][0].height = width << level;
1841
1842 mImageArray[0][0].format = internalFormat;
1843 }
1844
1845 return !textureOkay;
1846}
1847
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001848void 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 +00001849{
1850 unsigned int faceindex = faceIndex(face);
1851
1852 if (redefineTexture(level, internalFormat, width))
1853 {
1854 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001855 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001856 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001857 else
1858 {
1859 needRenderTarget();
1860 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001861
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001862 ASSERT(width == height);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001863
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001864 if (width > 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001865 {
1866 RECT sourceRect;
1867 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001868 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +00001869 sourceRect.top = y;
1870 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001871
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001872 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
1873
1874 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1875 dest->Release();
1876 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001877
1878 mImageArray[faceindex][level].width = width;
1879 mImageArray[faceindex][level].height = height;
1880 mImageArray[faceindex][level].format = internalFormat;
1881}
1882
1883IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(unsigned int faceIdentifier, unsigned int level)
1884{
1885 unsigned int faceIndex;
1886
1887 if (faceIdentifier < 6)
1888 {
1889 faceIndex = faceIdentifier;
1890 }
1891 else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
1892 {
1893 faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1894 }
1895 else
1896 {
1897 UNREACHABLE();
1898 faceIndex = 0;
1899 }
1900
1901 if (mTexture == NULL)
1902 {
1903 UNREACHABLE();
1904 return NULL;
1905 }
1906
1907 IDirect3DSurface9 *surface = NULL;
1908
1909 HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface);
1910
1911 return (SUCCEEDED(hr)) ? surface : NULL;
1912}
1913
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001914void 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 +00001915{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001916 GLsizei size = mImageArray[faceIndex(face)][level].width;
1917
1918 if (xoffset + width > size || yoffset + height > size)
1919 {
1920 return error(GL_INVALID_VALUE);
1921 }
1922
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001923 if (redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width))
1924 {
1925 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001926 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001927 }
1928 else
1929 {
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001930 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001931 }
1932
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001933 if (level < levelCount())
1934 {
1935 RECT sourceRect;
1936 sourceRect.left = x;
1937 sourceRect.right = x + width;
1938 sourceRect.top = y;
1939 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001940
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001941 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001942
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001943 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
1944 dest->Release();
1945 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001946}
1947
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001948bool TextureCubeMap::isCubeComplete() const
1949{
1950 if (mImageArray[0][0].width == 0)
1951 {
1952 return false;
1953 }
1954
1955 for (unsigned int f = 1; f < 6; f++)
1956 {
1957 if (mImageArray[f][0].width != mImageArray[0][0].width
1958 || mImageArray[f][0].format != mImageArray[0][0].format)
1959 {
1960 return false;
1961 }
1962 }
1963
1964 return true;
1965}
1966
1967void TextureCubeMap::generateMipmaps()
1968{
1969 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
1970 {
1971 return error(GL_INVALID_OPERATION);
1972 }
1973
1974 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1975 unsigned int q = log2(mImageArray[0][0].width);
1976 for (unsigned int f = 0; f < 6; f++)
1977 {
1978 for (unsigned int i = 1; i <= q; i++)
1979 {
1980 if (mImageArray[f][i].surface != NULL)
1981 {
1982 mImageArray[f][i].surface->Release();
1983 mImageArray[f][i].surface = NULL;
1984 }
1985
1986 mImageArray[f][i].dirty = false;
1987
1988 mImageArray[f][i].format = mImageArray[f][0].format;
1989 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
1990 mImageArray[f][i].height = mImageArray[f][i].width;
1991 }
1992 }
1993
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001994 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001995
apatrick@chromium.org9398a6b2010-09-20 19:07:49 +00001996 if (mTexture == NULL)
1997 {
1998 return;
1999 }
2000
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00002001 for (unsigned int f = 0; f < 6; f++)
2002 {
2003 for (unsigned int i = 1; i <= q; i++)
2004 {
2005 IDirect3DSurface9 *upper = getCubeMapSurface(f, i-1);
2006 IDirect3DSurface9 *lower = getCubeMapSurface(f, i);
2007
2008 if (upper != NULL && lower != NULL)
2009 {
2010 getBlitter()->boxFilter(upper, lower);
2011 }
2012
2013 if (upper != NULL) upper->Release();
2014 if (lower != NULL) lower->Release();
2015 }
2016 }
2017}
2018
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002019Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002020{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002021 if (!IsCubemapTextureTarget(target))
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002022 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002023 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002024 }
2025
2026 unsigned int face = faceIndex(target);
2027
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002028 if (mFaceProxies[face].get() == NULL)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002029 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002030 mFaceProxies[face].set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002031 }
2032
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002033 return mFaceProxies[face].get();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002034}
2035
2036IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2037{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002038 ASSERT(IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002039
2040 needRenderTarget();
apatrick@chromium.org4d5962c2010-09-20 19:02:30 +00002041
2042 if (mTexture == NULL)
2043 {
2044 return NULL;
2045 }
2046
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002047 IDirect3DSurface9 *renderTarget = NULL;
2048 mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex(target)), 0, &renderTarget);
2049
2050 return renderTarget;
2051}
2052
2053Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
enne@chromium.org0fa74632010-09-21 16:18:52 +00002054 : Colorbuffer(texture), mTexture(texture), mTarget(target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002055{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002056 ASSERT(target == GL_TEXTURE_2D || IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002057}
2058
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002059void Texture::TextureColorbufferProxy::addRef() const
2060{
2061 mTexture->addRef();
2062}
2063
2064void Texture::TextureColorbufferProxy::release() const
2065{
2066 mTexture->release();
2067}
2068
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002069IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
2070{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002071 if (mRenderTarget) mRenderTarget->Release();
2072
2073 mRenderTarget = mTexture->getRenderTarget(mTarget);
2074
2075 return mRenderTarget;
2076}
2077
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002078int Texture::TextureColorbufferProxy::getWidth() const
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002079{
daniel@transgaming.com866f3182010-05-20 19:28:22 +00002080 return mTexture->getWidth();
2081}
2082
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002083int Texture::TextureColorbufferProxy::getHeight() const
daniel@transgaming.com866f3182010-05-20 19:28:22 +00002084{
2085 return mTexture->getHeight();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002086}
2087
daniel@transgaming.com01868132010-08-24 19:21:17 +00002088GLenum Texture::TextureColorbufferProxy::getFormat() const
2089{
2090 return mTexture->getFormat();
2091}
2092
daniel@transgaming.com1297d922010-09-01 15:47:47 +00002093bool Texture::TextureColorbufferProxy::isFloatingPoint() const
2094{
2095 return mTexture->isFloatingPoint();
2096}
2097
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002098}