blob: 05632c46c6011e9e8f311024507f19054d1717ad [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.comd3958d72010-09-22 17:13:54 +0000780 if (!img->surface)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000781 {
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000782 createSurface(img->width, img->height, format, type, img);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000783 }
784
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000785 if (pixels != NULL && img->surface != NULL)
786 {
787 D3DLOCKED_RECT locked;
788 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
789
790 ASSERT(SUCCEEDED(result));
791
792 if (SUCCEEDED(result))
793 {
794 loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
795 img->surface->UnlockRect();
796 }
797
798 img->dirty = true;
799 }
800
daniel@transgaming.com31273552010-08-04 13:42:44 +0000801 return true;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000802}
803
daniel@transgaming.com01868132010-08-24 19:21:17 +0000804bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
805{
806 if (width + xoffset > img->width || height + yoffset > img->height)
807 {
808 error(GL_INVALID_VALUE);
809 return false;
810 }
811
812 if (format != getFormat())
813 {
814 error(GL_INVALID_OPERATION);
815 return false;
816 }
817
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000818 if (!img->surface)
daniel@transgaming.com01868132010-08-24 19:21:17 +0000819 {
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000820 createSurface(img->width, img->height, format, GL_UNSIGNED_BYTE, img);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000821 }
822
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000823 if (pixels != NULL && img->surface != NULL)
824 {
825 RECT updateRegion;
826 updateRegion.left = xoffset;
827 updateRegion.right = xoffset + width;
828 updateRegion.bottom = yoffset + height;
829 updateRegion.top = yoffset;
830
831 D3DLOCKED_RECT locked;
832 HRESULT result = img->surface->LockRect(&locked, &updateRegion, 0);
833
834 ASSERT(SUCCEEDED(result));
835
836 if (SUCCEEDED(result))
837 {
838 GLsizei inputPitch = ComputeCompressedPitch(width, format);
839 int rows = imageSize / inputPitch;
840 for (int i = 0; i < rows; ++i)
841 {
842 memcpy((void*)((BYTE*)locked.pBits + i * locked.Pitch), (void*)((BYTE*)pixels + i * inputPitch), inputPitch);
843 }
844 img->surface->UnlockRect();
845 }
846
847 img->dirty = true;
848 }
849
daniel@transgaming.com01868132010-08-24 19:21:17 +0000850 return true;
851}
852
enne@chromium.org0fa74632010-09-21 16:18:52 +0000853D3DFORMAT Texture::getD3DFormat() const
854{
855 return selectFormat(getFormat(), mType);
856}
857
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000858IDirect3DBaseTexture9 *Texture::getTexture()
859{
860 if (!isComplete())
861 {
862 return NULL;
863 }
864
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000865 if (mDirtyMetaData)
866 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000867 mBaseTexture = createTexture();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000868 mIsRenderable = false;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000869 }
870
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000871 if (mDirtyMetaData || dirtyImageData())
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000872 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000873 updateTexture();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000874 }
875
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000876 mDirtyMetaData = false;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000877 ASSERT(!dirtyImageData());
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000878
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000879 return mBaseTexture;
880}
881
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000882bool Texture::isDirty() const
883{
884 return (mDirty || mDirtyMetaData || dirtyImageData());
885}
886
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000887// Returns the top-level texture surface as a render target
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000888void Texture::needRenderTarget()
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000889{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000890 if (!mIsRenderable)
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000891 {
892 mBaseTexture = convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000893 mIsRenderable = true;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000894 }
895
896 if (dirtyImageData())
897 {
898 updateTexture();
899 }
900
901 mDirtyMetaData = false;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000902}
903
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000904void Texture::dropTexture()
905{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000906 if (mBaseTexture)
907 {
908 mBaseTexture = NULL;
909 }
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000910
911 mIsRenderable = false;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000912}
913
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000914void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000915{
916 mBaseTexture = newTexture;
917 mDirtyMetaData = false;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000918 mIsRenderable = renderable;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000919 mDirty = true;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000920}
921
922
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000923GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
924{
925 if (isPow2(width) && isPow2(height))
926 {
927 return maxlevel;
928 }
929 else
930 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000931 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
932 return 1;
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000933 }
934}
935
936GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
937{
938 return creationLevels(size, size, maxlevel);
939}
940
941int Texture::levelCount() const
942{
943 return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
944}
945
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000946Texture2D::Texture2D(GLuint id) : Texture(id)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000947{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000948 mTexture = NULL;
949}
950
951Texture2D::~Texture2D()
952{
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +0000953 mColorbufferProxy.set(NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000954
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000955 if (mTexture)
956 {
957 mTexture->Release();
958 mTexture = NULL;
959 }
960}
961
962GLenum Texture2D::getTarget() const
963{
964 return GL_TEXTURE_2D;
965}
966
daniel@transgaming.com01868132010-08-24 19:21:17 +0000967GLenum Texture2D::getFormat() const
968{
969 return mImageArray[0].format;
970}
971
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000972// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
973// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
974// Call this when a particular level of the texture must be defined with a specific format, width and height.
975//
976// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
977// 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 +0000978bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000979{
980 bool widthOkay = (mWidth >> level == width);
981 bool heightOkay = (mHeight >> level == height);
982
983 bool sizeOkay = ((widthOkay && heightOkay)
984 || (widthOkay && mHeight >> level == 0 && height == 1)
985 || (heightOkay && mWidth >> level == 0 && width == 1));
986
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000987 bool typeOkay = (type == mType);
988
989 bool textureOkay = (sizeOkay && typeOkay && internalFormat == mImageArray[0].format);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000990
991 if (!textureOkay)
992 {
993 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
994 mImageArray[0].format, mWidth, mHeight,
995 internalFormat, width, height);
996
997 // Purge all the levels and the texture.
998
999 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
1000 {
1001 if (mImageArray[i].surface != NULL)
1002 {
1003 mImageArray[i].dirty = false;
1004
1005 mImageArray[i].surface->Release();
1006 mImageArray[i].surface = NULL;
1007 }
1008 }
1009
1010 if (mTexture != NULL)
1011 {
1012 mTexture->Release();
1013 mTexture = NULL;
1014 dropTexture();
1015 }
1016
1017 mWidth = width << level;
1018 mHeight = height << level;
1019 mImageArray[0].format = internalFormat;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001020 mType = type;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001021 }
1022
1023 return !textureOkay;
1024}
1025
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001026void 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 +00001027{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001028 redefineTexture(level, internalFormat, width, height, type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001029
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001030 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001031}
1032
daniel@transgaming.com01868132010-08-24 19:21:17 +00001033void Texture2D::setCompressedImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1034{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001035 redefineTexture(level, internalFormat, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.com01868132010-08-24 19:21:17 +00001036
1037 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[level]);
1038}
1039
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001040void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1041{
1042 ASSERT(mImageArray[level].surface != NULL);
1043
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001044 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001045 {
1046 IDirect3DSurface9 *destLevel = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001047 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001048
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001049 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001050
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001051 if (SUCCEEDED(result))
1052 {
1053 Image *img = &mImageArray[level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001054
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001055 RECT sourceRect;
1056 sourceRect.left = xoffset;
1057 sourceRect.top = yoffset;
1058 sourceRect.right = xoffset + width;
1059 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001060
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001061 POINT destPoint;
1062 destPoint.x = xoffset;
1063 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001064
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001065 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
1066 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001067
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001068 destLevel->Release();
1069
1070 img->dirty = false;
1071 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001072 }
1073}
1074
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001075void 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 +00001076{
daniel@transgaming.com31273552010-08-04 13:42:44 +00001077 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1078 {
1079 commitRect(level, xoffset, yoffset, width, height);
1080 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001081}
1082
daniel@transgaming.com01868132010-08-24 19:21:17 +00001083void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1084{
1085 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1086 {
1087 commitRect(level, xoffset, yoffset, width, height);
1088 }
1089}
1090
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001091void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001092{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001093 if (redefineTexture(level, internalFormat, width, height, mType))
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001094 {
1095 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001096 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001097 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001098 else
1099 {
1100 needRenderTarget();
1101 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001102
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001103 if (width != 0 && height != 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001104 {
1105 RECT sourceRect;
1106 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001107 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +00001108 sourceRect.top = y;
1109 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001110
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001111 IDirect3DSurface9 *dest;
1112 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001113
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001114 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1115 dest->Release();
1116 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001117
1118 mImageArray[level].width = width;
1119 mImageArray[level].height = height;
1120 mImageArray[level].format = internalFormat;
1121}
1122
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001123void 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 +00001124{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001125 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1126 {
1127 return error(GL_INVALID_VALUE);
1128 }
1129
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001130 if (redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, mType))
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001131 {
1132 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001133 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001134 }
1135 else
1136 {
daniel@transgaming.comfc23fe22010-05-05 18:48:17 +00001137 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001138 }
1139
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001140 if (level < levelCount())
1141 {
1142 RECT sourceRect;
1143 sourceRect.left = x;
1144 sourceRect.right = x + width;
1145 sourceRect.top = y;
1146 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001147
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001148 IDirect3DSurface9 *dest;
1149 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001150
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001151 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
1152 dest->Release();
1153 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001154}
1155
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001156// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1157bool Texture2D::isComplete() const
1158{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001159 GLsizei width = mImageArray[0].width;
1160 GLsizei height = mImageArray[0].height;
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001161
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001162 if (width <= 0 || height <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001163 {
1164 return false;
1165 }
1166
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001167 bool mipmapping = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001168
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001169 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001170 {
1171 case GL_NEAREST:
1172 case GL_LINEAR:
1173 mipmapping = false;
1174 break;
1175 case GL_NEAREST_MIPMAP_NEAREST:
1176 case GL_LINEAR_MIPMAP_NEAREST:
1177 case GL_NEAREST_MIPMAP_LINEAR:
1178 case GL_LINEAR_MIPMAP_LINEAR:
1179 mipmapping = true;
1180 break;
1181 default: UNREACHABLE();
1182 }
1183
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001184 if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1185 (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1186 {
1187 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1188 {
1189 return false;
1190 }
1191 }
1192
1193
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001194 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1195 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1196 {
1197 return false;
1198 }
1199
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001200 if (mipmapping)
1201 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001202 if (!isPow2(width) || !isPow2(height))
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001203 {
1204 return false;
1205 }
1206
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001207 int q = log2(std::max(width, height));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001208
1209 for (int level = 1; level <= q; level++)
1210 {
1211 if (mImageArray[level].format != mImageArray[0].format)
1212 {
1213 return false;
1214 }
1215
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001216 if (mImageArray[level].width != std::max(1, width >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001217 {
1218 return false;
1219 }
1220
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001221 if (mImageArray[level].height != std::max(1, height >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001222 {
1223 return false;
1224 }
1225 }
1226 }
1227
1228 return true;
1229}
1230
daniel@transgaming.com01868132010-08-24 19:21:17 +00001231bool Texture2D::isCompressed() const
1232{
1233 return IsCompressed(getFormat());
1234}
1235
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001236// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001237IDirect3DBaseTexture9 *Texture2D::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001238{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001239 IDirect3DTexture9 *texture;
1240
1241 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001242 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001243
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001244 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001245
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001246 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001247 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001248 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001249 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001250 }
1251
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001252 if (mTexture) mTexture->Release();
1253 mTexture = texture;
1254 return texture;
1255}
1256
1257void Texture2D::updateTexture()
1258{
1259 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001260
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001261 int levels = levelCount();
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001262
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001263 for (int level = 0; level < levels; level++)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001264 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001265 if (mImageArray[level].dirty)
1266 {
1267 IDirect3DSurface9 *levelSurface = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001268 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001269
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001270 ASSERT(SUCCEEDED(result));
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001271
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001272 if (SUCCEEDED(result))
1273 {
1274 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1275 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001276
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001277 levelSurface->Release();
1278
1279 mImageArray[level].dirty = false;
1280 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001281 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001282 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001283}
1284
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001285IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001286{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001287 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001288
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001289 if (mWidth != 0 && mHeight != 0)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001290 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001291 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001292 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001293 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001294
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001295 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 +00001296
1297 if (FAILED(result))
1298 {
1299 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1300 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1301 }
1302
1303 if (mTexture != NULL)
1304 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001305 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001306 for (int i = 0; i < levels; i++)
1307 {
1308 IDirect3DSurface9 *source;
1309 result = mTexture->GetSurfaceLevel(i, &source);
1310
1311 if (FAILED(result))
1312 {
1313 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1314
1315 texture->Release();
1316
1317 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1318 }
1319
1320 IDirect3DSurface9 *dest;
1321 result = texture->GetSurfaceLevel(i, &dest);
1322
1323 if (FAILED(result))
1324 {
1325 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1326
1327 texture->Release();
1328 source->Release();
1329
1330 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1331 }
1332
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001333 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001334 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1335
1336 if (FAILED(result))
1337 {
1338 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1339
1340 texture->Release();
1341 source->Release();
1342 dest->Release();
1343
1344 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1345 }
1346
1347 source->Release();
1348 dest->Release();
1349 }
1350 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001351 }
1352
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001353 if (mTexture != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001354 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001355 mTexture->Release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001356 }
1357
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001358 mTexture = texture;
1359 return mTexture;
1360}
1361
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001362bool Texture2D::dirtyImageData() const
1363{
1364 int q = log2(std::max(mWidth, mHeight));
1365
1366 for (int i = 0; i <= q; i++)
1367 {
1368 if (mImageArray[i].dirty) return true;
1369 }
1370
1371 return false;
1372}
1373
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001374void Texture2D::generateMipmaps()
1375{
1376 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1377 {
1378 return error(GL_INVALID_OPERATION);
1379 }
1380
1381 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1382 unsigned int q = log2(std::max(mWidth, mHeight));
1383 for (unsigned int i = 1; i <= q; i++)
1384 {
1385 if (mImageArray[i].surface != NULL)
1386 {
1387 mImageArray[i].surface->Release();
1388 mImageArray[i].surface = NULL;
1389 }
1390
1391 mImageArray[i].dirty = false;
1392
1393 mImageArray[i].format = mImageArray[0].format;
1394 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1395 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
1396 }
1397
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001398 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001399
apatrick@chromium.org9398a6b2010-09-20 19:07:49 +00001400 if (mTexture == NULL)
1401 {
1402 return;
1403 }
1404
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001405 for (unsigned int i = 1; i <= q; i++)
1406 {
1407 IDirect3DSurface9 *upper = NULL;
1408 IDirect3DSurface9 *lower = NULL;
1409
1410 mTexture->GetSurfaceLevel(i-1, &upper);
1411 mTexture->GetSurfaceLevel(i, &lower);
1412
1413 if (upper != NULL && lower != NULL)
1414 {
1415 getBlitter()->boxFilter(upper, lower);
1416 }
1417
1418 if (upper != NULL) upper->Release();
1419 if (lower != NULL) lower->Release();
1420 }
1421}
1422
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001423Renderbuffer *Texture2D::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001424{
1425 if (target != GL_TEXTURE_2D)
1426 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001427 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001428 }
1429
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001430 if (mColorbufferProxy.get() == NULL)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001431 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001432 mColorbufferProxy.set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001433 }
1434
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001435 return mColorbufferProxy.get();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001436}
1437
1438IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1439{
1440 ASSERT(target == GL_TEXTURE_2D);
1441
1442 needRenderTarget();
1443
apatrick@chromium.org4d5962c2010-09-20 19:02:30 +00001444 if (mTexture == NULL)
1445 {
1446 return NULL;
1447 }
1448
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001449 IDirect3DSurface9 *renderTarget = NULL;
1450 mTexture->GetSurfaceLevel(0, &renderTarget);
1451
1452 return renderTarget;
1453}
1454
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001455TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001456{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001457 mTexture = NULL;
1458}
1459
1460TextureCubeMap::~TextureCubeMap()
1461{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001462 for (int i = 0; i < 6; i++)
1463 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001464 mFaceProxies[i].set(NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001465 }
1466
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001467 if (mTexture)
1468 {
1469 mTexture->Release();
1470 mTexture = NULL;
1471 }
1472}
1473
1474GLenum TextureCubeMap::getTarget() const
1475{
1476 return GL_TEXTURE_CUBE_MAP;
1477}
1478
daniel@transgaming.com01868132010-08-24 19:21:17 +00001479GLenum TextureCubeMap::getFormat() const
1480{
1481 return mImageArray[0][0].format;
1482}
1483
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001484void 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 +00001485{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001486 setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001487}
1488
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001489void 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 +00001490{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001491 setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001492}
1493
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001494void 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 +00001495{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001496 setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001497}
1498
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001499void 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 +00001500{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001501 setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001502}
1503
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001504void 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 +00001505{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001506 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001507}
1508
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001509void 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 +00001510{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001511 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001512}
1513
daniel@transgaming.com01868132010-08-24 19:21:17 +00001514void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1515{
1516 redefineTexture(level, internalFormat, width);
1517
1518 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[faceIndex(face)][level]);
1519}
1520
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001521void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1522{
1523 int face = faceIndex(faceTarget);
1524
1525 ASSERT(mImageArray[face][level].surface != NULL);
1526
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001527 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001528 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001529 IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level);
1530 ASSERT(destLevel != NULL);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001531
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001532 if (destLevel != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001533 {
1534 Image *img = &mImageArray[face][level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001535
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001536 RECT sourceRect;
1537 sourceRect.left = xoffset;
1538 sourceRect.top = yoffset;
1539 sourceRect.right = xoffset + width;
1540 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001541
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001542 POINT destPoint;
1543 destPoint.x = xoffset;
1544 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001545
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001546 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001547 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001548
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001549 destLevel->Release();
1550
1551 img->dirty = false;
1552 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001553 }
1554}
1555
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001556void 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 +00001557{
daniel@transgaming.com31273552010-08-04 13:42:44 +00001558 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(face)][level]))
1559 {
1560 commitRect(face, level, xoffset, yoffset, width, height);
1561 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001562}
1563
daniel@transgaming.com01868132010-08-24 19:21:17 +00001564void TextureCubeMap::subImageCompressed(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1565{
1566 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(face)][level]))
1567 {
1568 commitRect(face, level, xoffset, yoffset, width, height);
1569 }
1570}
1571
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001572// 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 +00001573bool TextureCubeMap::isComplete() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001574{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001575 int size = mImageArray[0][0].width;
1576
1577 if (size <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001578 {
1579 return false;
1580 }
1581
1582 bool mipmapping;
1583
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001584 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001585 {
1586 case GL_NEAREST:
1587 case GL_LINEAR:
1588 mipmapping = false;
1589 break;
1590 case GL_NEAREST_MIPMAP_NEAREST:
1591 case GL_LINEAR_MIPMAP_NEAREST:
1592 case GL_NEAREST_MIPMAP_LINEAR:
1593 case GL_LINEAR_MIPMAP_LINEAR:
1594 mipmapping = true;
1595 break;
1596 default: UNREACHABLE();
1597 }
1598
1599 for (int face = 0; face < 6; face++)
1600 {
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001601 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001602 {
1603 return false;
1604 }
1605 }
1606
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001607 if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1608 (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1609 {
1610 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1611 {
1612 return false;
1613 }
1614 }
1615
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001616 if (mipmapping)
1617 {
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001618 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1619 {
1620 return false;
1621 }
1622
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001623 int q = log2(size);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001624
1625 for (int face = 0; face < 6; face++)
1626 {
1627 for (int level = 1; level <= q; level++)
1628 {
1629 if (mImageArray[face][level].format != mImageArray[0][0].format)
1630 {
1631 return false;
1632 }
1633
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001634 if (mImageArray[face][level].width != std::max(1, size >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001635 {
1636 return false;
1637 }
1638
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001639 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001640 }
1641 }
1642 }
1643
1644 return true;
1645}
1646
daniel@transgaming.com01868132010-08-24 19:21:17 +00001647bool TextureCubeMap::isCompressed() const
1648{
1649 return IsCompressed(getFormat());
1650}
1651
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001652// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001653IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001654{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001655 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001656 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001657
1658 IDirect3DCubeTexture9 *texture;
1659
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001660 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001661
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001662 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001663 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001664 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001665 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001666 }
1667
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001668 if (mTexture) mTexture->Release();
1669
1670 mTexture = texture;
1671 return mTexture;
1672}
1673
1674void TextureCubeMap::updateTexture()
1675{
1676 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001677
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001678 for (int face = 0; face < 6; face++)
1679 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001680 int levels = levelCount();
1681 for (int level = 0; level < levels; level++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001682 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001683 Image *img = &mImageArray[face][level];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001684
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001685 if (img->dirty)
1686 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001687 IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level);
1688 ASSERT(levelSurface != NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001689
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001690 if (levelSurface != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001691 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001692 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001693 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001694
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001695 levelSurface->Release();
1696
1697 img->dirty = false;
1698 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001699 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001700 }
1701 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001702}
1703
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001704IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
1705{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001706 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001707
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001708 if (mWidth != 0)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001709 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001710 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001711 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001712 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001713
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001714 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001715
1716 if (FAILED(result))
1717 {
1718 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1719 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1720 }
1721
1722 if (mTexture != NULL)
1723 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001724 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001725 for (int f = 0; f < 6; f++)
1726 {
1727 for (int i = 0; i < levels; i++)
1728 {
1729 IDirect3DSurface9 *source;
1730 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
1731
1732 if (FAILED(result))
1733 {
1734 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1735
1736 texture->Release();
1737
1738 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1739 }
1740
1741 IDirect3DSurface9 *dest;
1742 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
1743
1744 if (FAILED(result))
1745 {
1746 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1747
1748 texture->Release();
1749 source->Release();
1750
1751 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1752 }
1753
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001754 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001755 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1756
1757 if (FAILED(result))
1758 {
1759 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1760
1761 texture->Release();
1762 source->Release();
1763 dest->Release();
1764
1765 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1766 }
1767 }
1768 }
1769 }
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001770 }
1771
1772 if (mTexture != NULL)
1773 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001774 mTexture->Release();
1775 }
1776
1777 mTexture = texture;
1778 return mTexture;
1779}
1780
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001781void 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 +00001782{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001783 redefineTexture(level, internalFormat, width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001784
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001785 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001786}
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001787
1788unsigned int TextureCubeMap::faceIndex(GLenum face)
1789{
1790 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1791 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1792 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1793 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1794 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1795
1796 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1797}
1798
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001799bool TextureCubeMap::dirtyImageData() const
1800{
1801 int q = log2(mWidth);
1802
1803 for (int f = 0; f < 6; f++)
1804 {
1805 for (int i = 0; i <= q; i++)
1806 {
1807 if (mImageArray[f][i].dirty) return true;
1808 }
1809 }
1810
1811 return false;
1812}
1813
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001814// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1815// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
1816// Call this when a particular level of the texture must be defined with a specific format, width and height.
1817//
1818// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
1819// a new size for the texture by working backwards from the given size.
1820bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
1821{
1822 // Are these settings compatible with level 0?
1823 bool sizeOkay = (mImageArray[0][0].width >> level == width);
1824
1825 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
1826
1827 if (!textureOkay)
1828 {
1829 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
1830 mImageArray[0][0].format, mImageArray[0][0].width,
1831 internalFormat, width);
1832
1833 // Purge all the levels and the texture.
1834 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
1835 {
1836 for (int f = 0; f < 6; f++)
1837 {
1838 if (mImageArray[f][i].surface != NULL)
1839 {
1840 mImageArray[f][i].dirty = false;
1841
1842 mImageArray[f][i].surface->Release();
1843 mImageArray[f][i].surface = NULL;
1844 }
1845 }
1846 }
1847
1848 if (mTexture != NULL)
1849 {
1850 mTexture->Release();
1851 mTexture = NULL;
1852 dropTexture();
1853 }
1854
1855 mWidth = width << level;
1856 mImageArray[0][0].width = width << level;
1857 mHeight = width << level;
1858 mImageArray[0][0].height = width << level;
1859
1860 mImageArray[0][0].format = internalFormat;
1861 }
1862
1863 return !textureOkay;
1864}
1865
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001866void 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 +00001867{
1868 unsigned int faceindex = faceIndex(face);
1869
1870 if (redefineTexture(level, internalFormat, width))
1871 {
1872 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001873 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001874 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001875 else
1876 {
1877 needRenderTarget();
1878 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001879
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001880 ASSERT(width == height);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001881
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001882 if (width > 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001883 {
1884 RECT sourceRect;
1885 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001886 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +00001887 sourceRect.top = y;
1888 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001889
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001890 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
1891
1892 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1893 dest->Release();
1894 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001895
1896 mImageArray[faceindex][level].width = width;
1897 mImageArray[faceindex][level].height = height;
1898 mImageArray[faceindex][level].format = internalFormat;
1899}
1900
1901IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(unsigned int faceIdentifier, unsigned int level)
1902{
1903 unsigned int faceIndex;
1904
1905 if (faceIdentifier < 6)
1906 {
1907 faceIndex = faceIdentifier;
1908 }
1909 else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
1910 {
1911 faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1912 }
1913 else
1914 {
1915 UNREACHABLE();
1916 faceIndex = 0;
1917 }
1918
1919 if (mTexture == NULL)
1920 {
1921 UNREACHABLE();
1922 return NULL;
1923 }
1924
1925 IDirect3DSurface9 *surface = NULL;
1926
1927 HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface);
1928
1929 return (SUCCEEDED(hr)) ? surface : NULL;
1930}
1931
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001932void 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 +00001933{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001934 GLsizei size = mImageArray[faceIndex(face)][level].width;
1935
1936 if (xoffset + width > size || yoffset + height > size)
1937 {
1938 return error(GL_INVALID_VALUE);
1939 }
1940
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001941 if (redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width))
1942 {
1943 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001944 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001945 }
1946 else
1947 {
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001948 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001949 }
1950
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001951 if (level < levelCount())
1952 {
1953 RECT sourceRect;
1954 sourceRect.left = x;
1955 sourceRect.right = x + width;
1956 sourceRect.top = y;
1957 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001958
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001959 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001960
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001961 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
1962 dest->Release();
1963 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001964}
1965
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001966bool TextureCubeMap::isCubeComplete() const
1967{
1968 if (mImageArray[0][0].width == 0)
1969 {
1970 return false;
1971 }
1972
1973 for (unsigned int f = 1; f < 6; f++)
1974 {
1975 if (mImageArray[f][0].width != mImageArray[0][0].width
1976 || mImageArray[f][0].format != mImageArray[0][0].format)
1977 {
1978 return false;
1979 }
1980 }
1981
1982 return true;
1983}
1984
1985void TextureCubeMap::generateMipmaps()
1986{
1987 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
1988 {
1989 return error(GL_INVALID_OPERATION);
1990 }
1991
1992 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1993 unsigned int q = log2(mImageArray[0][0].width);
1994 for (unsigned int f = 0; f < 6; f++)
1995 {
1996 for (unsigned int i = 1; i <= q; i++)
1997 {
1998 if (mImageArray[f][i].surface != NULL)
1999 {
2000 mImageArray[f][i].surface->Release();
2001 mImageArray[f][i].surface = NULL;
2002 }
2003
2004 mImageArray[f][i].dirty = false;
2005
2006 mImageArray[f][i].format = mImageArray[f][0].format;
2007 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2008 mImageArray[f][i].height = mImageArray[f][i].width;
2009 }
2010 }
2011
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002012 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00002013
apatrick@chromium.org9398a6b2010-09-20 19:07:49 +00002014 if (mTexture == NULL)
2015 {
2016 return;
2017 }
2018
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00002019 for (unsigned int f = 0; f < 6; f++)
2020 {
2021 for (unsigned int i = 1; i <= q; i++)
2022 {
2023 IDirect3DSurface9 *upper = getCubeMapSurface(f, i-1);
2024 IDirect3DSurface9 *lower = getCubeMapSurface(f, i);
2025
2026 if (upper != NULL && lower != NULL)
2027 {
2028 getBlitter()->boxFilter(upper, lower);
2029 }
2030
2031 if (upper != NULL) upper->Release();
2032 if (lower != NULL) lower->Release();
2033 }
2034 }
2035}
2036
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002037Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002038{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002039 if (!IsCubemapTextureTarget(target))
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002040 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002041 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002042 }
2043
2044 unsigned int face = faceIndex(target);
2045
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002046 if (mFaceProxies[face].get() == NULL)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002047 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002048 mFaceProxies[face].set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002049 }
2050
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002051 return mFaceProxies[face].get();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002052}
2053
2054IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2055{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002056 ASSERT(IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002057
2058 needRenderTarget();
daniel@transgaming.come979ead2010-09-23 18:03:14 +00002059
2060 if (mTexture == NULL)
2061 {
2062 return NULL;
apatrick@chromium.org4d5962c2010-09-20 19:02:30 +00002063 }
2064
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002065 IDirect3DSurface9 *renderTarget = NULL;
2066 mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex(target)), 0, &renderTarget);
2067
2068 return renderTarget;
2069}
2070
2071Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
enne@chromium.org0fa74632010-09-21 16:18:52 +00002072 : Colorbuffer(texture), mTexture(texture), mTarget(target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002073{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002074 ASSERT(target == GL_TEXTURE_2D || IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002075}
2076
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002077void Texture::TextureColorbufferProxy::addRef() const
2078{
2079 mTexture->addRef();
2080}
2081
2082void Texture::TextureColorbufferProxy::release() const
2083{
2084 mTexture->release();
2085}
2086
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002087IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
2088{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002089 if (mRenderTarget) mRenderTarget->Release();
2090
2091 mRenderTarget = mTexture->getRenderTarget(mTarget);
2092
2093 return mRenderTarget;
2094}
2095
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002096int Texture::TextureColorbufferProxy::getWidth() const
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002097{
daniel@transgaming.com866f3182010-05-20 19:28:22 +00002098 return mTexture->getWidth();
2099}
2100
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002101int Texture::TextureColorbufferProxy::getHeight() const
daniel@transgaming.com866f3182010-05-20 19:28:22 +00002102{
2103 return mTexture->getHeight();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002104}
2105
daniel@transgaming.com01868132010-08-24 19:21:17 +00002106GLenum Texture::TextureColorbufferProxy::getFormat() const
2107{
2108 return mTexture->getFormat();
2109}
2110
daniel@transgaming.com1297d922010-09-01 15:47:47 +00002111bool Texture::TextureColorbufferProxy::isFloatingPoint() const
2112{
2113 return mTexture->isFloatingPoint();
2114}
2115
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002116}