blob: fb2aab0dbd83de4567fb7b9ae092626b91783101 [file] [log] [blame]
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +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
11#include "libGLESv2/Texture.h"
12
13#include <d3dx9tex.h>
14
15#include <algorithm>
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +000016#include <intrin.h>
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000017
18#include "common/debug.h"
19
jbauman@chromium.orgae345802011-03-30 22:04:25 +000020#include "libEGL/Display.h"
21
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000022#include "libGLESv2/main.h"
23#include "libGLESv2/mathutil.h"
24#include "libGLESv2/utilities.h"
25#include "libGLESv2/Blit.h"
26#include "libGLESv2/Framebuffer.h"
27
28namespace gl
29{
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +000030unsigned int Texture::mCurrentSerial = 1;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000031
daniel@transgaming.comde631782011-11-09 17:45:04 +000032Image::Image()
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000033 : mWidth(0), mHeight(0), mDirty(false), mSurface(NULL), mFormat(GL_NONE), mType(GL_UNSIGNED_BYTE)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000034{
35}
36
daniel@transgaming.comde631782011-11-09 17:45:04 +000037Image::~Image()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000038{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000039 if (mSurface)
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +000040 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000041 mSurface->Release();
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +000042 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000043}
44
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000045void Image::redefine(GLenum format, GLsizei width, GLsizei height, GLenum type)
46{
daniel@transgaming.com4c0a7712011-11-09 17:45:19 +000047 if (mWidth != width ||
48 mHeight != height ||
49 mFormat != format ||
50 mType != type)
51 {
52 if (mSurface)
53 {
54 mSurface->Release();
55 mSurface = NULL;
56 }
57 }
58
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000059 mWidth = width;
60 mHeight = height;
61 mFormat = format;
62 mType = type;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000063}
64
65void Image::createSurface()
66{
67 if(mSurface)
68 {
69 return;
70 }
71
72 IDirect3DTexture9 *newTexture = NULL;
73 IDirect3DSurface9 *newSurface = NULL;
74
75 if (mWidth != 0 && mHeight != 0)
76 {
77 int levelToFetch = 0;
78 GLsizei requestWidth = mWidth;
79 GLsizei requestHeight = mHeight;
80 if (IsCompressed(mFormat) && (mWidth % 4 != 0 || mHeight % 4 != 0))
81 {
82 bool isMult4 = false;
83 int upsampleCount = 0;
84 while (!isMult4)
85 {
86 requestWidth <<= 1;
87 requestHeight <<= 1;
88 upsampleCount++;
89 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
90 {
91 isMult4 = true;
92 }
93 }
94 levelToFetch = upsampleCount;
95 }
96
97 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, getD3DFormat(),
98 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
99
100 if (FAILED(result))
101 {
102 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
103 return error(GL_OUT_OF_MEMORY);
104 }
105
106 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
107 newTexture->Release();
108 }
109
110 mSurface = newSurface;
111}
112
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +0000113HRESULT Image::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect)
114{
115 createSurface();
116
117 HRESULT result = D3DERR_INVALIDCALL;
118
119 if (mSurface)
120 {
121 result = mSurface->LockRect(lockedRect, rect, 0);
122 ASSERT(SUCCEEDED(result));
123
124 mDirty = true;
125 }
126
127 return result;
128}
129
130void Image::unlock()
131{
132 if (mSurface)
133 {
134 HRESULT result = mSurface->UnlockRect();
135 ASSERT(SUCCEEDED(result));
136 }
137}
138
daniel@transgaming.comde631782011-11-09 17:45:04 +0000139bool Image::isRenderable() const
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000140{
141 switch(getD3DFormat())
142 {
143 case D3DFMT_L8:
144 case D3DFMT_A8L8:
145 case D3DFMT_DXT1:
gman@chromium.org50c526d2011-08-10 05:19:44 +0000146 case D3DFMT_DXT3:
147 case D3DFMT_DXT5:
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000148 return false;
149 case D3DFMT_A8R8G8B8:
150 case D3DFMT_X8R8G8B8:
151 case D3DFMT_A16B16G16R16F:
152 case D3DFMT_A32B32G32R32F:
153 return true;
154 default:
155 UNREACHABLE();
156 }
157
158 return false;
159}
160
daniel@transgaming.comde631782011-11-09 17:45:04 +0000161D3DFORMAT Image::getD3DFormat() const
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000162{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000163 if (mFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
164 mFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000165 {
166 return D3DFMT_DXT1;
167 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000168 else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE)
gman@chromium.org50c526d2011-08-10 05:19:44 +0000169 {
170 return D3DFMT_DXT3;
171 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000172 else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE)
gman@chromium.org50c526d2011-08-10 05:19:44 +0000173 {
174 return D3DFMT_DXT5;
175 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000176 else if (mType == GL_FLOAT)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000177 {
178 return D3DFMT_A32B32G32R32F;
179 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000180 else if (mType == GL_HALF_FLOAT_OES)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000181 {
182 return D3DFMT_A16B16G16R16F;
183 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000184 else if (mType == GL_UNSIGNED_BYTE)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000185 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000186 if (mFormat == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000187 {
188 return D3DFMT_L8;
189 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000190 else if (mFormat == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000191 {
192 return D3DFMT_A8L8;
193 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000194 else if (mFormat == GL_RGB)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000195 {
196 return D3DFMT_X8R8G8B8;
197 }
198
199 return D3DFMT_A8R8G8B8;
200 }
201
202 return D3DFMT_A8R8G8B8;
203}
204
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +0000205Texture::Texture(GLuint id) : RefCountObject(id), mSerial(issueSerial())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000206{
207 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
208 mMagFilter = GL_LINEAR;
209 mWrapS = GL_REPEAT;
210 mWrapT = GL_REPEAT;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000211 mDirtyParameters = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000212
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000213 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +0000214
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000215 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000216}
217
218Texture::~Texture()
219{
220}
221
222Blit *Texture::getBlitter()
223{
224 Context *context = getContext();
225 return context->getBlitter();
226}
227
228// Returns true on successful filter state update (valid enum parameter)
229bool Texture::setMinFilter(GLenum filter)
230{
231 switch (filter)
232 {
233 case GL_NEAREST:
234 case GL_LINEAR:
235 case GL_NEAREST_MIPMAP_NEAREST:
236 case GL_LINEAR_MIPMAP_NEAREST:
237 case GL_NEAREST_MIPMAP_LINEAR:
238 case GL_LINEAR_MIPMAP_LINEAR:
239 {
240 if (mMinFilter != filter)
241 {
242 mMinFilter = filter;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000243 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000244 }
245 return true;
246 }
247 default:
248 return false;
249 }
250}
251
252// Returns true on successful filter state update (valid enum parameter)
253bool Texture::setMagFilter(GLenum filter)
254{
255 switch (filter)
256 {
257 case GL_NEAREST:
258 case GL_LINEAR:
259 {
260 if (mMagFilter != filter)
261 {
262 mMagFilter = filter;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000263 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000264 }
265 return true;
266 }
267 default:
268 return false;
269 }
270}
271
272// Returns true on successful wrap state update (valid enum parameter)
273bool Texture::setWrapS(GLenum wrap)
274{
275 switch (wrap)
276 {
277 case GL_REPEAT:
278 case GL_CLAMP_TO_EDGE:
279 case GL_MIRRORED_REPEAT:
280 {
281 if (mWrapS != wrap)
282 {
283 mWrapS = wrap;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000284 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000285 }
286 return true;
287 }
288 default:
289 return false;
290 }
291}
292
293// Returns true on successful wrap state update (valid enum parameter)
294bool Texture::setWrapT(GLenum wrap)
295{
296 switch (wrap)
297 {
298 case GL_REPEAT:
299 case GL_CLAMP_TO_EDGE:
300 case GL_MIRRORED_REPEAT:
301 {
302 if (mWrapT != wrap)
303 {
304 mWrapT = wrap;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000305 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000306 }
307 return true;
308 }
309 default:
310 return false;
311 }
312}
313
314GLenum Texture::getMinFilter() const
315{
316 return mMinFilter;
317}
318
319GLenum Texture::getMagFilter() const
320{
321 return mMagFilter;
322}
323
324GLenum Texture::getWrapS() const
325{
326 return mWrapS;
327}
328
329GLenum Texture::getWrapT() const
330{
331 return mWrapT;
332}
333
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000334// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
335// into the target pixel rectangle at output with outputPitch bytes in between each line.
336void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
337 GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const
338{
339 GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment);
340 input = ((char*)input) - inputPitch * (height - 1);
341
342 switch (type)
343 {
344 case GL_UNSIGNED_BYTE:
345 switch (format)
346 {
347 case GL_ALPHA:
348 loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
349 break;
350 case GL_LUMINANCE:
351 loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);
352 break;
353 case GL_LUMINANCE_ALPHA:
354 loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);
355 break;
356 case GL_RGB:
357 loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
358 break;
359 case GL_RGBA:
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000360 if (supportsSSE2())
361 {
362 loadRGBAUByteImageDataSSE2(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
363 }
364 else
365 {
366 loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
367 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000368 break;
369 case GL_BGRA_EXT:
370 loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
371 break;
372 default: UNREACHABLE();
373 }
374 break;
375 case GL_UNSIGNED_SHORT_5_6_5:
376 switch (format)
377 {
378 case GL_RGB:
379 loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
380 break;
381 default: UNREACHABLE();
382 }
383 break;
384 case GL_UNSIGNED_SHORT_4_4_4_4:
385 switch (format)
386 {
387 case GL_RGBA:
388 loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
389 break;
390 default: UNREACHABLE();
391 }
392 break;
393 case GL_UNSIGNED_SHORT_5_5_5_1:
394 switch (format)
395 {
396 case GL_RGBA:
397 loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
398 break;
399 default: UNREACHABLE();
400 }
401 break;
402 case GL_FLOAT:
403 switch (format)
404 {
405 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
406 case GL_ALPHA:
407 loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
408 break;
409 case GL_LUMINANCE:
410 loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
411 break;
412 case GL_LUMINANCE_ALPHA:
413 loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
414 break;
415 case GL_RGB:
416 loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
417 break;
418 case GL_RGBA:
419 loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
420 break;
421 default: UNREACHABLE();
422 }
423 break;
424 case GL_HALF_FLOAT_OES:
425 switch (format)
426 {
427 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
428 case GL_ALPHA:
429 loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
430 break;
431 case GL_LUMINANCE:
432 loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
433 break;
434 case GL_LUMINANCE_ALPHA:
435 loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
436 break;
437 case GL_RGB:
438 loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
439 break;
440 case GL_RGBA:
441 loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
442 break;
443 default: UNREACHABLE();
444 }
445 break;
446 default: UNREACHABLE();
447 }
448}
449
450void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
451 int inputPitch, const void *input, size_t outputPitch, void *output) const
452{
453 const unsigned char *source = NULL;
454 unsigned char *dest = NULL;
455
456 for (int y = 0; y < height; y++)
457 {
458 source = static_cast<const unsigned char*>(input) + y * inputPitch;
459 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
460 for (int x = 0; x < width; x++)
461 {
462 dest[4 * x + 0] = 0;
463 dest[4 * x + 1] = 0;
464 dest[4 * x + 2] = 0;
465 dest[4 * x + 3] = source[x];
466 }
467 }
468}
469
470void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
471 int inputPitch, const void *input, size_t outputPitch, void *output) const
472{
473 const float *source = NULL;
474 float *dest = NULL;
475
476 for (int y = 0; y < height; y++)
477 {
478 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
479 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
480 for (int x = 0; x < width; x++)
481 {
482 dest[4 * x + 0] = 0;
483 dest[4 * x + 1] = 0;
484 dest[4 * x + 2] = 0;
485 dest[4 * x + 3] = source[x];
486 }
487 }
488}
489
490void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
491 int inputPitch, const void *input, size_t outputPitch, void *output) const
492{
493 const unsigned short *source = NULL;
494 unsigned short *dest = NULL;
495
496 for (int y = 0; y < height; y++)
497 {
498 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
499 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
500 for (int x = 0; x < width; x++)
501 {
502 dest[4 * x + 0] = 0;
503 dest[4 * x + 1] = 0;
504 dest[4 * x + 2] = 0;
505 dest[4 * x + 3] = source[x];
506 }
507 }
508}
509
510void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
511 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
512{
513 const int destBytesPerPixel = native? 1: 4;
514 const unsigned char *source = NULL;
515 unsigned char *dest = NULL;
516
517 for (int y = 0; y < height; y++)
518 {
519 source = static_cast<const unsigned char*>(input) + y * inputPitch;
520 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
521
522 if (!native) // BGRA8 destination format
523 {
524 for (int x = 0; x < width; x++)
525 {
526 dest[4 * x + 0] = source[x];
527 dest[4 * x + 1] = source[x];
528 dest[4 * x + 2] = source[x];
529 dest[4 * x + 3] = 0xFF;
530 }
531 }
532 else // L8 destination format
533 {
534 memcpy(dest, source, width);
535 }
536 }
537}
538
539void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
540 int inputPitch, const void *input, size_t outputPitch, void *output) const
541{
542 const float *source = NULL;
543 float *dest = NULL;
544
545 for (int y = 0; y < height; y++)
546 {
547 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
548 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
549 for (int x = 0; x < width; x++)
550 {
551 dest[4 * x + 0] = source[x];
552 dest[4 * x + 1] = source[x];
553 dest[4 * x + 2] = source[x];
554 dest[4 * x + 3] = 1.0f;
555 }
556 }
557}
558
559void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
560 int inputPitch, const void *input, size_t outputPitch, void *output) const
561{
562 const unsigned short *source = NULL;
563 unsigned short *dest = NULL;
564
565 for (int y = 0; y < height; y++)
566 {
567 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
568 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
569 for (int x = 0; x < width; x++)
570 {
571 dest[4 * x + 0] = source[x];
572 dest[4 * x + 1] = source[x];
573 dest[4 * x + 2] = source[x];
574 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
575 }
576 }
577}
578
579void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
580 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
581{
582 const int destBytesPerPixel = native? 2: 4;
583 const unsigned char *source = NULL;
584 unsigned char *dest = NULL;
585
586 for (int y = 0; y < height; y++)
587 {
588 source = static_cast<const unsigned char*>(input) + y * inputPitch;
589 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
590
591 if (!native) // BGRA8 destination format
592 {
593 for (int x = 0; x < width; x++)
594 {
595 dest[4 * x + 0] = source[2*x+0];
596 dest[4 * x + 1] = source[2*x+0];
597 dest[4 * x + 2] = source[2*x+0];
598 dest[4 * x + 3] = source[2*x+1];
599 }
600 }
601 else
602 {
603 memcpy(dest, source, width * 2);
604 }
605 }
606}
607
608void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
609 int inputPitch, const void *input, size_t outputPitch, void *output) const
610{
611 const float *source = NULL;
612 float *dest = NULL;
613
614 for (int y = 0; y < height; y++)
615 {
616 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
617 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
618 for (int x = 0; x < width; x++)
619 {
620 dest[4 * x + 0] = source[2*x+0];
621 dest[4 * x + 1] = source[2*x+0];
622 dest[4 * x + 2] = source[2*x+0];
623 dest[4 * x + 3] = source[2*x+1];
624 }
625 }
626}
627
628void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
629 int inputPitch, const void *input, size_t outputPitch, void *output) const
630{
631 const unsigned short *source = NULL;
632 unsigned short *dest = NULL;
633
634 for (int y = 0; y < height; y++)
635 {
636 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
637 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
638 for (int x = 0; x < width; x++)
639 {
640 dest[4 * x + 0] = source[2*x+0];
641 dest[4 * x + 1] = source[2*x+0];
642 dest[4 * x + 2] = source[2*x+0];
643 dest[4 * x + 3] = source[2*x+1];
644 }
645 }
646}
647
648void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
649 int inputPitch, const void *input, size_t outputPitch, void *output) const
650{
651 const unsigned char *source = NULL;
652 unsigned char *dest = NULL;
653
654 for (int y = 0; y < height; y++)
655 {
656 source = static_cast<const unsigned char*>(input) + y * inputPitch;
657 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
658 for (int x = 0; x < width; x++)
659 {
660 dest[4 * x + 0] = source[x * 3 + 2];
661 dest[4 * x + 1] = source[x * 3 + 1];
662 dest[4 * x + 2] = source[x * 3 + 0];
663 dest[4 * x + 3] = 0xFF;
664 }
665 }
666}
667
668void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
669 int inputPitch, const void *input, size_t outputPitch, void *output) const
670{
671 const unsigned short *source = NULL;
672 unsigned char *dest = NULL;
673
674 for (int y = 0; y < height; y++)
675 {
676 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
677 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
678 for (int x = 0; x < width; x++)
679 {
680 unsigned short rgba = source[x];
681 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
682 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
683 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
684 dest[4 * x + 3] = 0xFF;
685 }
686 }
687}
688
689void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
690 int inputPitch, const void *input, size_t outputPitch, void *output) const
691{
692 const float *source = NULL;
693 float *dest = NULL;
694
695 for (int y = 0; y < height; y++)
696 {
697 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
698 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
699 for (int x = 0; x < width; x++)
700 {
701 dest[4 * x + 0] = source[x * 3 + 0];
702 dest[4 * x + 1] = source[x * 3 + 1];
703 dest[4 * x + 2] = source[x * 3 + 2];
704 dest[4 * x + 3] = 1.0f;
705 }
706 }
707}
708
709void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
710 int inputPitch, const void *input, size_t outputPitch, void *output) const
711{
712 const unsigned short *source = NULL;
713 unsigned short *dest = NULL;
714
715 for (int y = 0; y < height; y++)
716 {
717 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
718 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
719 for (int x = 0; x < width; x++)
720 {
721 dest[4 * x + 0] = source[x * 3 + 0];
722 dest[4 * x + 1] = source[x * 3 + 1];
723 dest[4 * x + 2] = source[x * 3 + 2];
724 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
725 }
726 }
727}
728
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000729void Texture::loadRGBAUByteImageDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
730 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000731{
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000732 const unsigned int *source = NULL;
733 unsigned int *dest = NULL;
734 __m128i brMask = _mm_set1_epi32(0x00ff00ff);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000735
736 for (int y = 0; y < height; y++)
737 {
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000738 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
739 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
740 int x = 0;
741
742 // Make output writes aligned
743 for (x = 0; ((reinterpret_cast<intptr_t>(&dest[x]) & 15) != 0) && x < width; x++)
744 {
745 unsigned int rgba = source[x];
746 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
747 }
748
749 for (; x + 3 < width; x += 4)
750 {
751 __m128i sourceData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&source[x]));
752 // Mask out g and a, which don't change
753 __m128i gaComponents = _mm_andnot_si128(brMask, sourceData);
754 // Mask out b and r
755 __m128i brComponents = _mm_and_si128(sourceData, brMask);
756 // Swap b and r
757 __m128i brSwapped = _mm_shufflehi_epi16(_mm_shufflelo_epi16(brComponents, _MM_SHUFFLE(2, 3, 0, 1)), _MM_SHUFFLE(2, 3, 0, 1));
758 __m128i result = _mm_or_si128(gaComponents, brSwapped);
759 _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), result);
760 }
761
762 // Perform leftover writes
763 for (; x < width; x++)
764 {
765 unsigned int rgba = source[x];
766 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
767 }
768 }
769}
770
771void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
772 int inputPitch, const void *input, size_t outputPitch, void *output) const
773{
774 const unsigned int *source = NULL;
775 unsigned int *dest = NULL;
776 for (int y = 0; y < height; y++)
777 {
778 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
779 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
780
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000781 for (int x = 0; x < width; x++)
782 {
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000783 unsigned int rgba = source[x];
784 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000785 }
786 }
787}
788
789void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
790 int inputPitch, const void *input, size_t outputPitch, void *output) const
791{
792 const unsigned short *source = NULL;
793 unsigned char *dest = NULL;
794
795 for (int y = 0; y < height; y++)
796 {
797 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
798 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
799 for (int x = 0; x < width; x++)
800 {
801 unsigned short rgba = source[x];
802 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
803 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
804 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
805 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
806 }
807 }
808}
809
810void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
811 int inputPitch, const void *input, size_t outputPitch, void *output) const
812{
813 const unsigned short *source = NULL;
814 unsigned char *dest = NULL;
815
816 for (int y = 0; y < height; y++)
817 {
818 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
819 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
820 for (int x = 0; x < width; x++)
821 {
822 unsigned short rgba = source[x];
823 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
824 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
825 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
826 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
827 }
828 }
829}
830
831void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
832 int inputPitch, const void *input, size_t outputPitch, void *output) const
833{
834 const float *source = NULL;
835 float *dest = NULL;
836
837 for (int y = 0; y < height; y++)
838 {
839 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
840 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
841 memcpy(dest, source, width * 16);
842 }
843}
844
845void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
846 int inputPitch, const void *input, size_t outputPitch, void *output) const
847{
848 const unsigned char *source = NULL;
849 unsigned char *dest = NULL;
850
851 for (int y = 0; y < height; y++)
852 {
853 source = static_cast<const unsigned char*>(input) + y * inputPitch;
854 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
855 memcpy(dest, source, width * 8);
856 }
857}
858
859void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
860 int inputPitch, const void *input, size_t outputPitch, void *output) const
861{
862 const unsigned char *source = NULL;
863 unsigned char *dest = NULL;
864
865 for (int y = 0; y < height; y++)
866 {
867 source = static_cast<const unsigned char*>(input) + y * inputPitch;
868 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
869 memcpy(dest, source, width*4);
870 }
871}
872
873void Texture::loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
gman@chromium.org50c526d2011-08-10 05:19:44 +0000874 int inputPitch, const void *input, size_t outputPitch, void *output) const {
875 switch (getD3DFormat())
876 {
877 case D3DFMT_DXT1:
878 loadDXT1ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
879 break;
880 case D3DFMT_DXT3:
881 loadDXT3ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
882 break;
883 case D3DFMT_DXT5:
884 loadDXT5ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
885 break;
886 }
887}
888
889static void FlipCopyDXT1BlockFull(const unsigned int* source, unsigned int* dest) {
890 // A DXT1 block layout is:
891 // [0-1] color0.
892 // [2-3] color1.
893 // [4-7] color bitmap, 2 bits per pixel.
894 // So each of the 4-7 bytes represents one line, flipping a block is just
895 // flipping those bytes.
896
897 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
898 dest[0] = source[0];
899
900 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
901 dest[1] = (source[1] >> 24) |
902 ((source[1] << 8) & 0x00FF0000) |
903 ((source[1] >> 8) & 0x0000FF00) |
904 (source[1] << 24);
905}
906
907// Flips the first 2 lines of a DXT1 block in the y direction.
908static void FlipCopyDXT1BlockHalf(const unsigned int* source, unsigned int* dest) {
909 // See layout above.
910 dest[0] = source[0];
911 dest[1] = ((source[1] << 8) & 0x0000FF00) |
912 ((source[1] >> 8) & 0x000000FF);
913}
914
915// Flips a full DXT3 block in the y direction.
916static void FlipCopyDXT3BlockFull(const unsigned int* source, unsigned int* dest) {
917 // A DXT3 block layout is:
918 // [0-7] alpha bitmap, 4 bits per pixel.
919 // [8-15] a DXT1 block.
920
921 // First and Second 32 bits are 4bit per pixel alpha and need to be flipped.
922 dest[0] = (source[1] >> 16) | (source[1] << 16);
923 dest[1] = (source[0] >> 16) | (source[0] << 16);
924
925 // And flip the DXT1 block using the above function.
926 FlipCopyDXT1BlockFull(source + 2, dest + 2);
927}
928
929// Flips the first 2 lines of a DXT3 block in the y direction.
930static void FlipCopyDXT3BlockHalf(const unsigned int* source, unsigned int* dest) {
931 // See layout above.
932 dest[0] = (source[1] >> 16) | (source[1] << 16);
933 FlipCopyDXT1BlockHalf(source + 2, dest + 2);
934}
935
936// Flips a full DXT5 block in the y direction.
937static void FlipCopyDXT5BlockFull(const unsigned int* source, unsigned int* dest) {
938 // A DXT5 block layout is:
939 // [0] alpha0.
940 // [1] alpha1.
941 // [2-7] alpha bitmap, 3 bits per pixel.
942 // [8-15] a DXT1 block.
943
944 // The alpha bitmap doesn't easily map lines to bytes, so we have to
945 // interpret it correctly. Extracted from
946 // http://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt :
947 //
948 // The 6 "bits" bytes of the block are decoded into one 48-bit integer:
949 //
950 // bits = bits_0 + 256 * (bits_1 + 256 * (bits_2 + 256 * (bits_3 +
951 // 256 * (bits_4 + 256 * bits_5))))
952 //
953 // bits is a 48-bit unsigned integer, from which a three-bit control code
954 // is extracted for a texel at location (x,y) in the block using:
955 //
956 // code(x,y) = bits[3*(4*y+x)+1..3*(4*y+x)+0]
957 //
958 // where bit 47 is the most significant and bit 0 is the least
959 // significant bit.
960 const unsigned char* sourceBytes = static_cast<const unsigned char*>(static_cast<const void*>(source));
961 unsigned char* destBytes = static_cast<unsigned char*>(static_cast<void*>(dest));
962 unsigned int line_0_1 = sourceBytes[2] + 256 * (sourceBytes[3] + 256 * sourceBytes[4]);
963 unsigned int line_2_3 = sourceBytes[5] + 256 * (sourceBytes[6] + 256 * sourceBytes[7]);
964 // swap lines 0 and 1 in line_0_1.
965 unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) |
966 ((line_0_1 & 0xfff000) >> 12);
967 // swap lines 2 and 3 in line_2_3.
968 unsigned int line_3_2 = ((line_2_3 & 0x000fff) << 12) |
969 ((line_2_3 & 0xfff000) >> 12);
970 destBytes[0] = sourceBytes[0];
971 destBytes[1] = sourceBytes[1];
972 destBytes[2] = line_3_2 & 0xff;
973 destBytes[3] = (line_3_2 & 0xff00) >> 8;
gman@chromium.org2ac3e732011-08-10 07:59:47 +0000974 destBytes[4] = (line_3_2 & 0xff0000) >> 16;
gman@chromium.org50c526d2011-08-10 05:19:44 +0000975 destBytes[5] = line_1_0 & 0xff;
976 destBytes[6] = (line_1_0 & 0xff00) >> 8;
gman@chromium.org2ac3e732011-08-10 07:59:47 +0000977 destBytes[7] = (line_1_0 & 0xff0000) >> 16;
gman@chromium.org50c526d2011-08-10 05:19:44 +0000978
979 // And flip the DXT1 block using the above function.
980 FlipCopyDXT1BlockFull(source + 2, dest + 2);
981}
982
983// Flips the first 2 lines of a DXT5 block in the y direction.
984static void FlipCopyDXT5BlockHalf(const unsigned int* source, unsigned int* dest) {
985 // See layout above.
986 const unsigned char* sourceBytes = static_cast<const unsigned char*>(static_cast<const void*>(source));
987 unsigned char* destBytes = static_cast<unsigned char*>(static_cast<void*>(dest));
988 unsigned int line_0_1 = sourceBytes[2] + 256 * (sourceBytes[3] + 256 * sourceBytes[4]);
989 unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) |
990 ((line_0_1 & 0xfff000) >> 12);
991 destBytes[0] = sourceBytes[0];
992 destBytes[1] = sourceBytes[1];
993 destBytes[2] = line_1_0 & 0xff;
994 destBytes[3] = (line_1_0 & 0xff00) >> 8;
gman@chromium.org25c5cf62011-08-10 08:07:54 +0000995 destBytes[4] = (line_1_0 & 0xff0000) >> 16;
gman@chromium.org50c526d2011-08-10 05:19:44 +0000996 FlipCopyDXT1BlockHalf(source + 2, dest + 2);
997}
998
999void Texture::loadDXT1ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001000 int inputPitch, const void *input, size_t outputPitch, void *output) const
1001{
1002 ASSERT(xoffset % 4 == 0);
1003 ASSERT(yoffset % 4 == 0);
1004 ASSERT(width % 4 == 0 || width == 2 || width == 1);
1005 ASSERT(inputPitch % 8 == 0);
1006 ASSERT(outputPitch % 8 == 0);
1007
1008 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
1009 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
1010
gman@chromium.org50c526d2011-08-10 05:19:44 +00001011 // Round width up in case it is less than 4.
1012 int blocksAcross = (width + 3) / 4;
1013 int intsAcross = blocksAcross * 2;
1014
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001015 switch (height)
1016 {
1017 case 1:
gman@chromium.org50c526d2011-08-10 05:19:44 +00001018 for (int x = 0; x < intsAcross; x += 2)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001019 {
gman@chromium.org50c526d2011-08-10 05:19:44 +00001020 // just copy the block
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001021 dest[x] = source[x];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001022 dest[x + 1] = source[x + 1];
1023 }
1024 break;
1025 case 2:
gman@chromium.org50c526d2011-08-10 05:19:44 +00001026 for (int x = 0; x < intsAcross; x += 2)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001027 {
gman@chromium.org50c526d2011-08-10 05:19:44 +00001028 FlipCopyDXT1BlockHalf(source + x, dest + x);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001029 }
1030 break;
1031 default:
1032 ASSERT(height % 4 == 0);
1033 for (int y = 0; y < height / 4; ++y)
1034 {
1035 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
1036 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
1037
gman@chromium.org50c526d2011-08-10 05:19:44 +00001038 for (int x = 0; x < intsAcross; x += 2)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001039 {
gman@chromium.org50c526d2011-08-10 05:19:44 +00001040 FlipCopyDXT1BlockFull(source + x, dest + x);
1041 }
1042 }
1043 break;
1044 }
1045}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001046
gman@chromium.org50c526d2011-08-10 05:19:44 +00001047void Texture::loadDXT3ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
1048 int inputPitch, const void *input, size_t outputPitch, void *output) const
1049{
1050 ASSERT(xoffset % 4 == 0);
1051 ASSERT(yoffset % 4 == 0);
1052 ASSERT(width % 4 == 0 || width == 2 || width == 1);
1053 ASSERT(inputPitch % 16 == 0);
1054 ASSERT(outputPitch % 16 == 0);
1055
1056 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
1057 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
1058
1059 // Round width up in case it is less than 4.
1060 int blocksAcross = (width + 3) / 4;
1061 int intsAcross = blocksAcross * 4;
1062
1063 switch (height)
1064 {
1065 case 1:
1066 for (int x = 0; x < intsAcross; x += 4)
1067 {
1068 // just copy the block
1069 dest[x] = source[x];
1070 dest[x + 1] = source[x + 1];
1071 dest[x + 2] = source[x + 2];
1072 dest[x + 3] = source[x + 3];
1073 }
1074 break;
1075 case 2:
1076 for (int x = 0; x < intsAcross; x += 4)
1077 {
1078 FlipCopyDXT3BlockHalf(source + x, dest + x);
1079 }
1080 break;
1081 default:
1082 ASSERT(height % 4 == 0);
1083 for (int y = 0; y < height / 4; ++y)
1084 {
1085 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
1086 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
1087
1088 for (int x = 0; x < intsAcross; x += 4)
1089 {
1090 FlipCopyDXT3BlockFull(source + x, dest + x);
1091 }
1092 }
1093 break;
1094 }
1095}
1096
1097void Texture::loadDXT5ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
1098 int inputPitch, const void *input, size_t outputPitch, void *output) const
1099{
1100 ASSERT(xoffset % 4 == 0);
1101 ASSERT(yoffset % 4 == 0);
1102 ASSERT(width % 4 == 0 || width == 2 || width == 1);
1103 ASSERT(inputPitch % 16 == 0);
1104 ASSERT(outputPitch % 16 == 0);
1105
1106 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
1107 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
1108
1109 // Round width up in case it is less than 4.
1110 int blocksAcross = (width + 3) / 4;
1111 int intsAcross = blocksAcross * 4;
1112
1113 switch (height)
1114 {
1115 case 1:
1116 for (int x = 0; x < intsAcross; x += 4)
1117 {
1118 // just copy the block
1119 dest[x] = source[x];
1120 dest[x + 1] = source[x + 1];
1121 dest[x + 2] = source[x + 2];
1122 dest[x + 3] = source[x + 3];
1123 }
1124 break;
1125 case 2:
1126 for (int x = 0; x < intsAcross; x += 4)
1127 {
1128 FlipCopyDXT5BlockHalf(source + x, dest + x);
1129 }
1130 break;
1131 default:
1132 ASSERT(height % 4 == 0);
gman@chromium.org2ac3e732011-08-10 07:59:47 +00001133 for (int y = 0; y < height / 4; ++y)
gman@chromium.org50c526d2011-08-10 05:19:44 +00001134 {
1135 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
1136 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
1137
1138 for (int x = 0; x < intsAcross; x += 4)
1139 {
1140 FlipCopyDXT5BlockFull(source + x, dest + x);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001141 }
1142 }
1143 break;
1144 }
1145}
1146
daniel@transgaming.com61208202011-03-21 16:38:50 +00001147void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001148{
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00001149 image->createSurface();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001150
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001151 if (pixels != NULL && image->getSurface() != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001152 {
1153 D3DSURFACE_DESC description;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001154 image->getSurface()->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001155
1156 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001157 HRESULT result = image->lock(&locked, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001158
1159 if (SUCCEEDED(result))
1160 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001161 loadImageData(0, 0, image->getWidth(), image->getHeight(), image->getFormat(), image->getType(), unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001162 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001163 }
1164
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001165 image->markDirty();
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001166 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001167 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001168}
1169
daniel@transgaming.com61208202011-03-21 16:38:50 +00001170void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001171{
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00001172 image->createSurface();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001173
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001174 if (pixels != NULL && image->getSurface() != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001175 {
1176 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001177 HRESULT result = image->lock(&locked, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001178
1179 if (SUCCEEDED(result))
1180 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001181 int inputPitch = ComputeCompressedPitch(image->getWidth(), image->getFormat());
1182 int inputSize = ComputeCompressedSize(image->getWidth(), image->getHeight(), image->getFormat());
1183 loadCompressedImageData(0, 0, image->getWidth(), image->getHeight(), -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001184 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001185 }
1186
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001187 image->markDirty();
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001188 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001189 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001190}
1191
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001192bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001193{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001194 if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001195 {
1196 error(GL_INVALID_VALUE);
1197 return false;
1198 }
1199
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001200 if (IsCompressed(image->getFormat()))
jbauman@chromium.orge2f954c2011-05-03 20:45:27 +00001201 {
1202 error(GL_INVALID_OPERATION);
1203 return false;
1204 }
1205
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001206 if (format != image->getFormat())
jbauman@chromium.orge2f954c2011-05-03 20:45:27 +00001207 {
1208 error(GL_INVALID_OPERATION);
1209 return false;
1210 }
1211
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00001212 image->createSurface();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001213
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001214 if (pixels != NULL && image->getSurface() != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001215 {
1216 D3DSURFACE_DESC description;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001217 image->getSurface()->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001218
1219 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001220 HRESULT result = image->lock(&locked, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001221
1222 if (SUCCEEDED(result))
1223 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001224 loadImageData(xoffset, transformPixelYOffset(yoffset, height, image->getHeight()), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001225 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001226 }
1227
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001228 image->markDirty();
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001229 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001230 }
1231
1232 return true;
1233}
1234
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001235bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001236{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001237 if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001238 {
1239 error(GL_INVALID_VALUE);
1240 return false;
1241 }
1242
1243 if (format != getInternalFormat())
1244 {
1245 error(GL_INVALID_OPERATION);
1246 return false;
1247 }
1248
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001249 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001250 {
1251 RECT updateRegion;
1252 updateRegion.left = xoffset;
1253 updateRegion.right = xoffset + width;
1254 updateRegion.bottom = yoffset + height;
1255 updateRegion.top = yoffset;
1256
1257 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001258 HRESULT result = image->lock(&locked, &updateRegion);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001259
1260 if (SUCCEEDED(result))
1261 {
1262 int inputPitch = ComputeCompressedPitch(width, format);
1263 int inputSize = ComputeCompressedSize(width, height, format);
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001264 loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, image->getHeight()), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001265 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001266 }
1267
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001268 image->markDirty();
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001269 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001270 }
1271
1272 return true;
1273}
1274
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001275// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
1276void Texture::copyToImage(Image *image, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001277{
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00001278 image->createSurface();
1279
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001280 if (!image->getSurface())
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001281 {
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00001282 ERR("Failed to create an image surface.");
1283 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001284 }
1285
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001286 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001287 IDirect3DSurface9 *renderTargetData = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001288 D3DSURFACE_DESC description;
1289 renderTarget->GetDesc(&description);
1290
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001291 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001292
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001293 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001294 {
1295 ERR("Could not create matching destination surface.");
1296 return error(GL_OUT_OF_MEMORY);
1297 }
1298
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001299 result = device->GetRenderTargetData(renderTarget, renderTargetData);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001300
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001301 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001302 {
1303 ERR("GetRenderTargetData unexpectedly failed.");
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001304 renderTargetData->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001305 return error(GL_OUT_OF_MEMORY);
1306 }
1307
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001308 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001309 int destYOffset = transformPixelYOffset(yoffset, height, image->getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001310 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001311
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001312 if (image->isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001313 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001314 result = D3DXLoadSurfaceFromSurface(image->getSurface(), NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0);
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001315
1316 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001317 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001318 ERR("Copying surfaces unexpectedly failed.");
1319 renderTargetData->Release();
1320 return error(GL_OUT_OF_MEMORY);
1321 }
1322 }
1323 else
1324 {
1325 D3DLOCKED_RECT sourceLock = {0};
1326 result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001327
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001328 if (FAILED(result))
1329 {
1330 ERR("Failed to lock the source surface (rectangle might be invalid).");
1331 renderTargetData->Release();
1332 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001333 }
1334
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001335 D3DLOCKED_RECT destLock = {0};
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001336 result = image->lock(&destLock, &destRect);
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001337
1338 if (FAILED(result))
1339 {
1340 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1341 renderTargetData->UnlockRect();
1342 renderTargetData->Release();
1343 return error(GL_OUT_OF_MEMORY);
1344 }
1345
1346 if (destLock.pBits && sourceLock.pBits)
1347 {
1348 unsigned char *source = (unsigned char*)sourceLock.pBits;
1349 unsigned char *dest = (unsigned char*)destLock.pBits;
1350
1351 switch (description.Format)
1352 {
1353 case D3DFMT_X8R8G8B8:
1354 case D3DFMT_A8R8G8B8:
1355 switch(image->getD3DFormat())
1356 {
1357 case D3DFMT_L8:
1358 for(int y = 0; y < height; y++)
1359 {
1360 for(int x = 0; x < width; x++)
1361 {
1362 dest[x] = source[x * 4 + 2];
1363 }
1364
1365 source += sourceLock.Pitch;
1366 dest += destLock.Pitch;
1367 }
1368 break;
1369 case D3DFMT_A8L8:
1370 for(int y = 0; y < height; y++)
1371 {
1372 for(int x = 0; x < width; x++)
1373 {
1374 dest[x * 2 + 0] = source[x * 4 + 2];
1375 dest[x * 2 + 1] = source[x * 4 + 3];
1376 }
1377
1378 source += sourceLock.Pitch;
1379 dest += destLock.Pitch;
1380 }
1381 break;
1382 default:
1383 UNREACHABLE();
1384 }
1385 break;
1386 case D3DFMT_R5G6B5:
1387 switch(image->getD3DFormat())
1388 {
1389 case D3DFMT_L8:
1390 for(int y = 0; y < height; y++)
1391 {
1392 for(int x = 0; x < width; x++)
1393 {
1394 unsigned char red = source[x * 2 + 1] & 0xF8;
1395 dest[x] = red | (red >> 5);
1396 }
1397
1398 source += sourceLock.Pitch;
1399 dest += destLock.Pitch;
1400 }
1401 break;
1402 default:
1403 UNREACHABLE();
1404 }
1405 break;
1406 case D3DFMT_A1R5G5B5:
1407 switch(image->getD3DFormat())
1408 {
1409 case D3DFMT_L8:
1410 for(int y = 0; y < height; y++)
1411 {
1412 for(int x = 0; x < width; x++)
1413 {
1414 unsigned char red = source[x * 2 + 1] & 0x7C;
1415 dest[x] = (red << 1) | (red >> 4);
1416 }
1417
1418 source += sourceLock.Pitch;
1419 dest += destLock.Pitch;
1420 }
1421 break;
1422 case D3DFMT_A8L8:
1423 for(int y = 0; y < height; y++)
1424 {
1425 for(int x = 0; x < width; x++)
1426 {
1427 unsigned char red = source[x * 2 + 1] & 0x7C;
1428 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1429 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1430 }
1431
1432 source += sourceLock.Pitch;
1433 dest += destLock.Pitch;
1434 }
1435 break;
1436 default:
1437 UNREACHABLE();
1438 }
1439 break;
1440 default:
1441 UNREACHABLE();
1442 }
1443 }
1444
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001445 image->unlock();
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001446 renderTargetData->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001447 }
1448
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001449 renderTargetData->Release();
1450
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001451 image->markDirty();
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001452 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001453}
1454
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001455IDirect3DBaseTexture9 *Texture::getTexture()
1456{
1457 if (!isComplete())
1458 {
1459 return NULL;
1460 }
1461
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001462 if (!getBaseTexture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001463 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001464 createTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001465 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001466
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +00001467 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001468
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001469 return getBaseTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001470}
1471
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001472bool Texture::hasDirtyParameters() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001473{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001474 return mDirtyParameters;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001475}
1476
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001477bool Texture::hasDirtyImages() const
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001478{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001479 return mDirtyImages;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001480}
1481
1482void Texture::resetDirty()
1483{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001484 mDirtyParameters = false;
1485 mDirtyImages = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001486}
1487
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001488unsigned int Texture::getSerial() const
1489{
1490 return mSerial;
1491}
1492
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001493GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1494{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001495 if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001496 {
1497 return maxlevel;
1498 }
1499 else
1500 {
1501 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1502 return 1;
1503 }
1504}
1505
1506GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1507{
1508 return creationLevels(size, size, maxlevel);
1509}
1510
1511int Texture::levelCount() const
1512{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001513 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001514}
1515
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001516unsigned int Texture::issueSerial()
1517{
1518 return mCurrentSerial++;
1519}
1520
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001521Texture2D::Texture2D(GLuint id) : Texture(id)
1522{
1523 mTexture = NULL;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001524 mSurface = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001525}
1526
1527Texture2D::~Texture2D()
1528{
1529 mColorbufferProxy.set(NULL);
1530
1531 if (mTexture)
1532 {
1533 mTexture->Release();
1534 mTexture = NULL;
1535 }
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001536
1537 if (mSurface)
1538 {
1539 mSurface->setBoundTexture(NULL);
1540 mSurface = NULL;
1541 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001542}
1543
1544GLenum Texture2D::getTarget() const
1545{
1546 return GL_TEXTURE_2D;
1547}
1548
daniel@transgaming.com61208202011-03-21 16:38:50 +00001549GLsizei Texture2D::getWidth() const
1550{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001551 return mImageArray[0].getWidth();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001552}
1553
1554GLsizei Texture2D::getHeight() const
1555{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001556 return mImageArray[0].getHeight();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001557}
1558
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001559GLenum Texture2D::getInternalFormat() const
1560{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001561 return mImageArray[0].getFormat();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001562}
1563
daniel@transgaming.com61208202011-03-21 16:38:50 +00001564GLenum Texture2D::getType() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001565{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001566 return mImageArray[0].getType();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001567}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001568
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001569D3DFORMAT Texture2D::getD3DFormat() const
1570{
1571 return mImageArray[0].getD3DFormat();
1572}
1573
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001574void Texture2D::redefineImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type, bool forceRedefine)
daniel@transgaming.com61208202011-03-21 16:38:50 +00001575{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001576 GLsizei textureWidth = mImageArray[0].getWidth();
1577 GLsizei textureHeight = mImageArray[0].getHeight();
1578 GLenum textureFormat = mImageArray[0].getFormat();
1579 GLenum textureType = mImageArray[0].getType();
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001580
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001581 mImageArray[level].redefine(format, width, height, type);
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00001582
daniel@transgaming.com61208202011-03-21 16:38:50 +00001583 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001584 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001585 return;
1586 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001587
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001588 bool widthOkay = (textureWidth >> level == width) || (textureWidth >> level == 0 && width == 1);
1589 bool heightOkay = (textureHeight >> level == height) || (textureHeight >> level == 0 && height == 1);
1590 bool textureOkay = (widthOkay && heightOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00001591
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00001592 if (!textureOkay || forceRedefine || mSurface)
daniel@transgaming.com61208202011-03-21 16:38:50 +00001593 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001594 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1595 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001596 mImageArray[i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001597 }
1598
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001599 mTexture->Release();
1600 mTexture = NULL;
1601 mDirtyImages = true;
1602 mIsRenderable = false;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001603
1604 if (mSurface)
1605 {
1606 mSurface->setBoundTexture(NULL);
1607 mSurface = NULL;
1608 }
apatrick@chromium.org57a2cd62011-06-08 00:04:07 +00001609
1610 mColorbufferProxy.set(NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001611 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001612}
1613
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001614void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001615{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001616 redefineImage(level, format, width, height, type, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001617
daniel@transgaming.com61208202011-03-21 16:38:50 +00001618 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001619}
1620
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001621void Texture2D::bindTexImage(egl::Surface *surface)
1622{
1623 GLenum format;
1624
1625 switch(surface->getFormat())
1626 {
1627 case D3DFMT_A8R8G8B8:
1628 format = GL_RGBA;
1629 break;
1630 case D3DFMT_X8R8G8B8:
1631 format = GL_RGB;
1632 break;
1633 default:
1634 UNIMPLEMENTED();
1635 return;
1636 }
1637
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001638 redefineImage(0, format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE, true);
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001639
1640 IDirect3DTexture9 *texture = surface->getOffscreenTexture();
1641
1642 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001643 mDirtyImages = true;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001644 mIsRenderable = true;
1645 mSurface = surface;
1646 mSurface->setBoundTexture(this);
1647}
1648
1649void Texture2D::releaseTexImage()
1650{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001651 redefineImage(0, GL_RGB, 0, 0, GL_UNSIGNED_BYTE, true);
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001652}
1653
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001654void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001655{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001656 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001657
daniel@transgaming.com61208202011-03-21 16:38:50 +00001658 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001659}
1660
1661void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1662{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001663 ASSERT(mImageArray[level].getSurface() != NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001664
1665 if (level < levelCount())
1666 {
1667 IDirect3DSurface9 *destLevel = NULL;
1668 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1669
1670 ASSERT(SUCCEEDED(result));
1671
1672 if (SUCCEEDED(result))
1673 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001674 Image *image = &mImageArray[level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001675
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001676 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->getHeight());;
daniel@transgaming.comb612f882011-11-09 17:44:31 +00001677 POINT destPoint = {sourceRect.left, sourceRect.top};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001678
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001679 result = getDevice()->UpdateSurface(image->getSurface(), &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001680 ASSERT(SUCCEEDED(result));
1681
1682 destLevel->Release();
1683
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001684 image->markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001685 }
1686 }
1687}
1688
1689void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1690{
1691 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1692 {
1693 commitRect(level, xoffset, yoffset, width, height);
1694 }
1695}
1696
1697void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1698{
1699 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1700 {
1701 commitRect(level, xoffset, yoffset, width, height);
1702 }
1703}
1704
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001705void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001706{
1707 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1708
1709 if (!renderTarget)
1710 {
1711 ERR("Failed to retrieve the render target.");
1712 return error(GL_OUT_OF_MEMORY);
1713 }
1714
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001715 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001716
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001717 if (!mImageArray[level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001718 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001719 copyToImage(&mImageArray[level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001720 }
1721 else
1722 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001723 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001724 {
1725 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001726 }
daniel@transgaming.com3b3c1d42011-06-08 20:38:09 +00001727
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001728 mImageArray[level].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001729
1730 if (width != 0 && height != 0 && level < levelCount())
1731 {
1732 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1733 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1734 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1735 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1736 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001737
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001738 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[level].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001739
1740 IDirect3DSurface9 *dest;
1741 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1742
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001743 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001744 dest->Release();
1745 }
1746 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001747}
1748
1749void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1750{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001751 if (xoffset + width > mImageArray[level].getWidth() || yoffset + height > mImageArray[level].getHeight())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001752 {
1753 return error(GL_INVALID_VALUE);
1754 }
1755
1756 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1757
1758 if (!renderTarget)
1759 {
1760 ERR("Failed to retrieve the render target.");
1761 return error(GL_OUT_OF_MEMORY);
1762 }
1763
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001764 if (!mImageArray[level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001765 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001766 copyToImage(&mImageArray[level], xoffset, yoffset, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001767 }
1768 else
1769 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001770 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001771 {
1772 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001773 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001774
1775 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001776
1777 if (level < levelCount())
1778 {
1779 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1780 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1781 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1782 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1783 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1784
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001785 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001786
1787 IDirect3DSurface9 *dest;
1788 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1789
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001790 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0].getFormat(), xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001791 dest->Release();
1792 }
1793 }
1794}
1795
1796// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1797bool Texture2D::isComplete() const
1798{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001799 GLsizei width = mImageArray[0].getWidth();
1800 GLsizei height = mImageArray[0].getHeight();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001801
1802 if (width <= 0 || height <= 0)
1803 {
1804 return false;
1805 }
1806
1807 bool mipmapping = false;
1808
1809 switch (mMinFilter)
1810 {
1811 case GL_NEAREST:
1812 case GL_LINEAR:
1813 mipmapping = false;
1814 break;
1815 case GL_NEAREST_MIPMAP_NEAREST:
1816 case GL_LINEAR_MIPMAP_NEAREST:
1817 case GL_NEAREST_MIPMAP_LINEAR:
1818 case GL_LINEAR_MIPMAP_LINEAR:
1819 mipmapping = true;
1820 break;
1821 default: UNREACHABLE();
1822 }
1823
1824 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1825 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1826 {
1827 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1828 {
1829 return false;
1830 }
1831 }
1832
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001833 bool npot = getContext()->supportsNonPower2Texture();
1834
1835 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001836 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001837 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
1838 (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1839 {
1840 return false;
1841 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001842 }
1843
1844 if (mipmapping)
1845 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001846 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001847 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001848 if (!isPow2(width) || !isPow2(height))
1849 {
1850 return false;
1851 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001852 }
1853
1854 int q = log2(std::max(width, height));
1855
1856 for (int level = 1; level <= q; level++)
1857 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001858 if (mImageArray[level].getFormat() != mImageArray[0].getFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001859 {
1860 return false;
1861 }
1862
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001863 if (mImageArray[level].getType() != mImageArray[0].getType())
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001864 {
1865 return false;
1866 }
1867
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001868 if (mImageArray[level].getWidth() != std::max(1, width >> level))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001869 {
1870 return false;
1871 }
1872
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001873 if (mImageArray[level].getHeight() != std::max(1, height >> level))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001874 {
1875 return false;
1876 }
1877 }
1878 }
1879
1880 return true;
1881}
1882
1883bool Texture2D::isCompressed() const
1884{
1885 return IsCompressed(getInternalFormat());
1886}
1887
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001888IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1889{
1890 return mTexture;
1891}
1892
1893// Constructs a Direct3D 9 texture resource from the texture images
1894void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001895{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001896 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001897 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001898 GLint levels = creationLevels(mImageArray[0].getWidth(), mImageArray[0].getHeight(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001899
daniel@transgaming.com61208202011-03-21 16:38:50 +00001900 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001901 HRESULT result = device->CreateTexture(mImageArray[0].getWidth(), mImageArray[0].getHeight(), levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001902
1903 if (FAILED(result))
1904 {
1905 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001906 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001907 }
1908
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001909 if (mTexture)
1910 {
1911 mTexture->Release();
1912 }
1913
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001914 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001915 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001916 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001917}
1918
1919void Texture2D::updateTexture()
1920{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001921 int levels = levelCount();
1922
1923 for (int level = 0; level < levels; level++)
1924 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00001925 Image *image = &mImageArray[level];
1926
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001927 if (image->isDirty())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001928 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001929 commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001930 }
1931 }
1932}
1933
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001934void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001935{
1936 IDirect3DTexture9 *texture = NULL;
1937
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001938 if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001939 {
1940 egl::Display *display = getDisplay();
1941 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001942 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001943 GLint levels = creationLevels(mImageArray[0].getWidth(), mImageArray[0].getHeight(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001944
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001945 HRESULT result = device->CreateTexture(mImageArray[0].getWidth(), mImageArray[0].getHeight(), levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001946
1947 if (FAILED(result))
1948 {
1949 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001950 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001951 }
1952
1953 if (mTexture != NULL)
1954 {
1955 int levels = levelCount();
1956 for (int i = 0; i < levels; i++)
1957 {
1958 IDirect3DSurface9 *source;
1959 result = mTexture->GetSurfaceLevel(i, &source);
1960
1961 if (FAILED(result))
1962 {
1963 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1964
1965 texture->Release();
1966
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001967 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001968 }
1969
1970 IDirect3DSurface9 *dest;
1971 result = texture->GetSurfaceLevel(i, &dest);
1972
1973 if (FAILED(result))
1974 {
1975 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1976
1977 texture->Release();
1978 source->Release();
1979
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001980 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001981 }
1982
1983 display->endScene();
1984 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1985
1986 if (FAILED(result))
1987 {
1988 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1989
1990 texture->Release();
1991 source->Release();
1992 dest->Release();
1993
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001994 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001995 }
1996
1997 source->Release();
1998 dest->Release();
1999 }
2000 }
2001 }
2002
2003 if (mTexture != NULL)
2004 {
2005 mTexture->Release();
2006 }
2007
2008 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002009 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002010 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002011}
2012
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002013void Texture2D::generateMipmaps()
2014{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002015 if (!getContext()->supportsNonPower2Texture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002016 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002017 if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight()))
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002018 {
2019 return error(GL_INVALID_OPERATION);
2020 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002021 }
2022
2023 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002024 unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight()));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002025 for (unsigned int i = 1; i <= q; i++)
2026 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002027 mImageArray[i].redefine(mImageArray[0].getFormat(),
2028 std::max(mImageArray[0].getWidth() >> i, 1),
2029 std::max(mImageArray[0].getHeight() >> i, 1),
2030 mImageArray[0].getType());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002031 }
2032
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002033 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002034 {
2035 if (mTexture == NULL)
2036 {
2037 ERR(" failed because mTexture was null.");
2038 return;
2039 }
2040
2041 for (unsigned int i = 1; i <= q; i++)
2042 {
2043 IDirect3DSurface9 *upper = NULL;
2044 IDirect3DSurface9 *lower = NULL;
2045
2046 mTexture->GetSurfaceLevel(i-1, &upper);
2047 mTexture->GetSurfaceLevel(i, &lower);
2048
2049 if (upper != NULL && lower != NULL)
2050 {
2051 getBlitter()->boxFilter(upper, lower);
2052 }
2053
2054 if (upper != NULL) upper->Release();
2055 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002056
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002057 mImageArray[i].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002058 }
2059 }
2060 else
2061 {
2062 for (unsigned int i = 1; i <= q; i++)
2063 {
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00002064 mImageArray[i].createSurface();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002065
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002066 if (mImageArray[i].getSurface() == NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002067 {
2068 return error(GL_OUT_OF_MEMORY);
2069 }
2070
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002071 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].getSurface(), NULL, NULL, mImageArray[i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0)))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002072 {
2073 ERR(" failed to load filter %d to %d.", i - 1, i);
2074 }
2075
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002076 mImageArray[i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002077 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002078 }
2079}
2080
2081Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
2082{
2083 if (target != GL_TEXTURE_2D)
2084 {
2085 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2086 }
2087
2088 if (mColorbufferProxy.get() == NULL)
2089 {
2090 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2091 }
2092
2093 return mColorbufferProxy.get();
2094}
2095
2096IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
2097{
2098 ASSERT(target == GL_TEXTURE_2D);
2099
daniel@transgaming.com61208202011-03-21 16:38:50 +00002100 if (!mIsRenderable)
2101 {
2102 convertToRenderTarget();
2103 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002104
2105 if (mTexture == NULL)
2106 {
2107 return NULL;
2108 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002109
2110 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002111
2112 IDirect3DSurface9 *renderTarget = NULL;
2113 mTexture->GetSurfaceLevel(0, &renderTarget);
2114
2115 return renderTarget;
2116}
2117
2118TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
2119{
2120 mTexture = NULL;
2121}
2122
2123TextureCubeMap::~TextureCubeMap()
2124{
2125 for (int i = 0; i < 6; i++)
2126 {
2127 mFaceProxies[i].set(NULL);
2128 }
2129
2130 if (mTexture)
2131 {
2132 mTexture->Release();
2133 mTexture = NULL;
2134 }
2135}
2136
2137GLenum TextureCubeMap::getTarget() const
2138{
2139 return GL_TEXTURE_CUBE_MAP;
2140}
2141
daniel@transgaming.com61208202011-03-21 16:38:50 +00002142GLsizei TextureCubeMap::getWidth() const
2143{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002144 return mImageArray[0][0].getWidth();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002145}
2146
2147GLsizei TextureCubeMap::getHeight() const
2148{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002149 return mImageArray[0][0].getHeight();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002150}
2151
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002152GLenum TextureCubeMap::getInternalFormat() const
2153{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002154 return mImageArray[0][0].getFormat();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002155}
2156
daniel@transgaming.com61208202011-03-21 16:38:50 +00002157GLenum TextureCubeMap::getType() const
2158{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002159 return mImageArray[0][0].getType();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002160}
2161
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002162D3DFORMAT TextureCubeMap::getD3DFormat() const
2163{
2164 return mImageArray[0][0].getD3DFormat();
2165}
2166
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002167void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002168{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002169 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002170}
2171
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002172void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002173{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002174 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002175}
2176
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002177void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002178{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002179 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002180}
2181
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002182void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002183{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002184 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002185}
2186
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002187void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002188{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002189 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002190}
2191
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002192void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002193{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002194 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002195}
2196
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002197void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002198{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002199 redefineImage(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002200
daniel@transgaming.com61208202011-03-21 16:38:50 +00002201 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002202}
2203
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002204void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002205{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002206 ASSERT(mImageArray[face][level].getSurface() != NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002207
2208 if (level < levelCount())
2209 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002210 IDirect3DSurface9 *destLevel = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002211 ASSERT(destLevel != NULL);
2212
2213 if (destLevel != NULL)
2214 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002215 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002216
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002217 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->getHeight());;
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002218 POINT destPoint = {sourceRect.left, sourceRect.top};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002219
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002220 HRESULT result = getDevice()->UpdateSurface(image->getSurface(), &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002221 ASSERT(SUCCEEDED(result));
2222
2223 destLevel->Release();
2224
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002225 image->markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002226 }
2227 }
2228}
2229
2230void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2231{
2232 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
2233 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002234 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002235 }
2236}
2237
2238void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
2239{
2240 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
2241 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002242 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002243 }
2244}
2245
2246// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
2247bool TextureCubeMap::isComplete() const
2248{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002249 int size = mImageArray[0][0].getWidth();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002250
2251 if (size <= 0)
2252 {
2253 return false;
2254 }
2255
2256 bool mipmapping;
2257
2258 switch (mMinFilter)
2259 {
2260 case GL_NEAREST:
2261 case GL_LINEAR:
2262 mipmapping = false;
2263 break;
2264 case GL_NEAREST_MIPMAP_NEAREST:
2265 case GL_LINEAR_MIPMAP_NEAREST:
2266 case GL_NEAREST_MIPMAP_LINEAR:
2267 case GL_LINEAR_MIPMAP_LINEAR:
2268 mipmapping = true;
2269 break;
2270 default: UNREACHABLE();
2271 }
2272
2273 for (int face = 0; face < 6; face++)
2274 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002275 if (mImageArray[face][0].getWidth() != size || mImageArray[face][0].getHeight() != size)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002276 {
2277 return false;
2278 }
2279 }
2280
2281 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
2282 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
2283 {
2284 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
2285 {
2286 return false;
2287 }
2288 }
2289
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002290 bool npot = getContext()->supportsNonPower2Texture();
2291
2292 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002293 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002294 if ((getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE) && !isPow2(size))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002295 {
2296 return false;
2297 }
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002298 }
2299
2300 if (mipmapping)
2301 {
2302 if (!npot)
2303 {
2304 if (!isPow2(size))
2305 {
2306 return false;
2307 }
2308 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002309
2310 int q = log2(size);
2311
2312 for (int face = 0; face < 6; face++)
2313 {
2314 for (int level = 1; level <= q; level++)
2315 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002316 if (mImageArray[face][level].getFormat() != mImageArray[0][0].getFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002317 {
2318 return false;
2319 }
2320
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002321 if (mImageArray[face][level].getType() != mImageArray[0][0].getType())
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002322 {
2323 return false;
2324 }
2325
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002326 if (mImageArray[face][level].getWidth() != std::max(1, size >> level))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002327 {
2328 return false;
2329 }
2330
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002331 ASSERT(mImageArray[face][level].getHeight() == mImageArray[face][level].getWidth());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002332 }
2333 }
2334 }
2335
2336 return true;
2337}
2338
2339bool TextureCubeMap::isCompressed() const
2340{
2341 return IsCompressed(getInternalFormat());
2342}
2343
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002344IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
2345{
2346 return mTexture;
2347}
2348
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002349// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002350void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002351{
2352 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002353 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002354 GLint levels = creationLevels(mImageArray[0][0].getWidth(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002355
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002356 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002357 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].getWidth(), levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002358
2359 if (FAILED(result))
2360 {
2361 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002362 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002363 }
2364
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002365 if (mTexture)
2366 {
2367 mTexture->Release();
2368 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002369
2370 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002371 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002372 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002373}
2374
2375void TextureCubeMap::updateTexture()
2376{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002377 for (int face = 0; face < 6; face++)
2378 {
2379 int levels = levelCount();
2380 for (int level = 0; level < levels; level++)
2381 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002382 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002383
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00002384 if (image->isDirty())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002385 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002386 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002387 }
2388 }
2389 }
2390}
2391
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002392void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002393{
2394 IDirect3DCubeTexture9 *texture = NULL;
2395
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002396 if (mImageArray[0][0].getWidth() != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002397 {
2398 egl::Display *display = getDisplay();
2399 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002400 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002401 GLint levels = creationLevels(mImageArray[0][0].getWidth(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002402
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002403 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].getWidth(), levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002404
2405 if (FAILED(result))
2406 {
2407 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002408 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002409 }
2410
2411 if (mTexture != NULL)
2412 {
2413 int levels = levelCount();
2414 for (int f = 0; f < 6; f++)
2415 {
2416 for (int i = 0; i < levels; i++)
2417 {
2418 IDirect3DSurface9 *source;
2419 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2420
2421 if (FAILED(result))
2422 {
2423 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2424
2425 texture->Release();
2426
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002427 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002428 }
2429
2430 IDirect3DSurface9 *dest;
2431 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2432
2433 if (FAILED(result))
2434 {
2435 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2436
2437 texture->Release();
2438 source->Release();
2439
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002440 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002441 }
2442
2443 display->endScene();
2444 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2445
2446 if (FAILED(result))
2447 {
2448 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2449
2450 texture->Release();
2451 source->Release();
2452 dest->Release();
2453
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002454 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002455 }
daniel@transgaming.coma1a86202011-08-09 13:41:08 +00002456
2457 source->Release();
2458 dest->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002459 }
2460 }
2461 }
2462 }
2463
2464 if (mTexture != NULL)
2465 {
2466 mTexture->Release();
2467 }
2468
2469 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002470 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002471 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002472}
2473
daniel@transgaming.com61208202011-03-21 16:38:50 +00002474void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002475{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002476 redefineImage(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002477
daniel@transgaming.com61208202011-03-21 16:38:50 +00002478 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002479}
2480
2481unsigned int TextureCubeMap::faceIndex(GLenum face)
2482{
2483 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2484 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2485 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2486 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2487 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2488
2489 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2490}
2491
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002492void TextureCubeMap::redefineImage(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002493{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002494 GLsizei textureWidth = mImageArray[0][0].getWidth();
2495 GLsizei textureHeight = mImageArray[0][0].getHeight();
2496 GLenum textureFormat = mImageArray[0][0].getFormat();
2497 GLenum textureType = mImageArray[0][0].getType();
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002498
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002499 mImageArray[face][level].redefine(format, width, height, type);
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00002500
daniel@transgaming.com61208202011-03-21 16:38:50 +00002501 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002502 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002503 return;
2504 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002505
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002506 bool sizeOkay = (textureWidth >> level == width);
2507 bool textureOkay = (sizeOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002508
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00002509 if (!textureOkay)
daniel@transgaming.com61208202011-03-21 16:38:50 +00002510 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002511 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2512 {
2513 for (int f = 0; f < 6; f++)
2514 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002515 mImageArray[f][i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002516 }
2517 }
2518
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002519 mTexture->Release();
2520 mTexture = NULL;
2521 mDirtyImages = true;
2522 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002523 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002524}
2525
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002526void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002527{
2528 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2529
2530 if (!renderTarget)
2531 {
2532 ERR("Failed to retrieve the render target.");
2533 return error(GL_OUT_OF_MEMORY);
2534 }
2535
2536 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002537 redefineImage(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002538
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002539 if (!mImageArray[faceindex][level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002540 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002541 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002542 }
2543 else
2544 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002545 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002546 {
2547 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002548 }
daniel@transgaming.com3b3c1d42011-06-08 20:38:09 +00002549
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002550 mImageArray[faceindex][level].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002551
2552 ASSERT(width == height);
2553
2554 if (width > 0 && level < levelCount())
2555 {
2556 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2557 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2558 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2559 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2560 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2561
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002562 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[faceindex][level].getWidth());
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002563
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002564 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2565
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002566 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002567 dest->Release();
2568 }
2569 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002570}
2571
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002572IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum target, unsigned int level)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002573{
2574 if (mTexture == NULL)
2575 {
2576 UNREACHABLE();
2577 return NULL;
2578 }
2579
2580 IDirect3DSurface9 *surface = NULL;
2581
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002582 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), level, &surface);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002583
2584 return (SUCCEEDED(hr)) ? surface : NULL;
2585}
2586
2587void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2588{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002589 GLsizei size = mImageArray[faceIndex(target)][level].getWidth();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002590
2591 if (xoffset + width > size || yoffset + height > size)
2592 {
2593 return error(GL_INVALID_VALUE);
2594 }
2595
2596 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2597
2598 if (!renderTarget)
2599 {
2600 ERR("Failed to retrieve the render target.");
2601 return error(GL_OUT_OF_MEMORY);
2602 }
2603
2604 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com01dae852011-11-09 17:44:53 +00002605
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002606 if (!mImageArray[faceindex][level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002607 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002608 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002609 }
2610 else
2611 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002612 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002613 {
2614 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002615 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002616
2617 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002618
2619 if (level < levelCount())
2620 {
2621 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2622 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2623 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2624 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2625 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2626
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002627 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].getWidth());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002628
2629 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2630
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002631 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0][0].getFormat(), xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002632 dest->Release();
2633 }
2634 }
2635}
2636
2637bool TextureCubeMap::isCubeComplete() const
2638{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002639 if (mImageArray[0][0].getWidth() == 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002640 {
2641 return false;
2642 }
2643
2644 for (unsigned int f = 1; f < 6; f++)
2645 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002646 if (mImageArray[f][0].getWidth() != mImageArray[0][0].getWidth()
2647 || mImageArray[f][0].getFormat() != mImageArray[0][0].getFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002648 {
2649 return false;
2650 }
2651 }
2652
2653 return true;
2654}
2655
2656void TextureCubeMap::generateMipmaps()
2657{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002658 if (!isCubeComplete())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002659 {
2660 return error(GL_INVALID_OPERATION);
2661 }
2662
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002663 if (!getContext()->supportsNonPower2Texture())
2664 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002665 if (!isPow2(mImageArray[0][0].getWidth()))
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002666 {
2667 return error(GL_INVALID_OPERATION);
2668 }
2669 }
2670
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002671 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002672 unsigned int q = log2(mImageArray[0][0].getWidth());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002673 for (unsigned int f = 0; f < 6; f++)
2674 {
2675 for (unsigned int i = 1; i <= q; i++)
2676 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002677 mImageArray[f][i].redefine(mImageArray[f][0].getFormat(),
2678 std::max(mImageArray[f][0].getWidth() >> i, 1),
2679 std::max(mImageArray[f][0].getWidth() >> i, 1),
2680 mImageArray[f][0].getType());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002681 }
2682 }
2683
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002684 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002685 {
2686 if (mTexture == NULL)
2687 {
2688 return;
2689 }
2690
2691 for (unsigned int f = 0; f < 6; f++)
2692 {
2693 for (unsigned int i = 1; i <= q; i++)
2694 {
2695 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2696 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2697
2698 if (upper != NULL && lower != NULL)
2699 {
2700 getBlitter()->boxFilter(upper, lower);
2701 }
2702
2703 if (upper != NULL) upper->Release();
2704 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002705
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002706 mImageArray[f][i].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002707 }
2708 }
2709 }
2710 else
2711 {
2712 for (unsigned int f = 0; f < 6; f++)
2713 {
2714 for (unsigned int i = 1; i <= q; i++)
2715 {
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00002716 mImageArray[f][i].createSurface();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002717 if (mImageArray[f][i].getSurface() == NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002718 {
2719 return error(GL_OUT_OF_MEMORY);
2720 }
2721
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002722 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].getSurface(), NULL, NULL, mImageArray[f][i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0)))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002723 {
2724 ERR(" failed to load filter %d to %d.", i - 1, i);
2725 }
2726
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002727 mImageArray[f][i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002728 }
2729 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002730 }
2731}
2732
2733Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2734{
2735 if (!IsCubemapTextureTarget(target))
2736 {
2737 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2738 }
2739
2740 unsigned int face = faceIndex(target);
2741
2742 if (mFaceProxies[face].get() == NULL)
2743 {
2744 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2745 }
2746
2747 return mFaceProxies[face].get();
2748}
2749
2750IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2751{
2752 ASSERT(IsCubemapTextureTarget(target));
2753
daniel@transgaming.com61208202011-03-21 16:38:50 +00002754 if (!mIsRenderable)
2755 {
2756 convertToRenderTarget();
2757 }
2758
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002759 if (mTexture == NULL)
2760 {
2761 return NULL;
2762 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002763
2764 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002765
2766 IDirect3DSurface9 *renderTarget = NULL;
2767 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2768
2769 return renderTarget;
2770}
2771
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002772}