blob: c633f1f9e7799957d72707bad4eed43f65fe910f [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{
47 mWidth = width;
48 mHeight = height;
49 mFormat = format;
50 mType = type;
51
52 if (mSurface)
53 {
54 mSurface->Release();
55 mSurface = NULL;
56 mDirty = true;
57 }
58
59 createSurface();
60}
61
62void Image::createSurface()
63{
64 if(mSurface)
65 {
66 return;
67 }
68
69 IDirect3DTexture9 *newTexture = NULL;
70 IDirect3DSurface9 *newSurface = NULL;
71
72 if (mWidth != 0 && mHeight != 0)
73 {
74 int levelToFetch = 0;
75 GLsizei requestWidth = mWidth;
76 GLsizei requestHeight = mHeight;
77 if (IsCompressed(mFormat) && (mWidth % 4 != 0 || mHeight % 4 != 0))
78 {
79 bool isMult4 = false;
80 int upsampleCount = 0;
81 while (!isMult4)
82 {
83 requestWidth <<= 1;
84 requestHeight <<= 1;
85 upsampleCount++;
86 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
87 {
88 isMult4 = true;
89 }
90 }
91 levelToFetch = upsampleCount;
92 }
93
94 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, getD3DFormat(),
95 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
96
97 if (FAILED(result))
98 {
99 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
100 return error(GL_OUT_OF_MEMORY);
101 }
102
103 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
104 newTexture->Release();
105 }
106
107 mSurface = newSurface;
108}
109
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +0000110HRESULT Image::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect)
111{
112 createSurface();
113
114 HRESULT result = D3DERR_INVALIDCALL;
115
116 if (mSurface)
117 {
118 result = mSurface->LockRect(lockedRect, rect, 0);
119 ASSERT(SUCCEEDED(result));
120
121 mDirty = true;
122 }
123
124 return result;
125}
126
127void Image::unlock()
128{
129 if (mSurface)
130 {
131 HRESULT result = mSurface->UnlockRect();
132 ASSERT(SUCCEEDED(result));
133 }
134}
135
daniel@transgaming.comde631782011-11-09 17:45:04 +0000136bool Image::isRenderable() const
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000137{
138 switch(getD3DFormat())
139 {
140 case D3DFMT_L8:
141 case D3DFMT_A8L8:
142 case D3DFMT_DXT1:
gman@chromium.org50c526d2011-08-10 05:19:44 +0000143 case D3DFMT_DXT3:
144 case D3DFMT_DXT5:
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000145 return false;
146 case D3DFMT_A8R8G8B8:
147 case D3DFMT_X8R8G8B8:
148 case D3DFMT_A16B16G16R16F:
149 case D3DFMT_A32B32G32R32F:
150 return true;
151 default:
152 UNREACHABLE();
153 }
154
155 return false;
156}
157
daniel@transgaming.comde631782011-11-09 17:45:04 +0000158D3DFORMAT Image::getD3DFormat() const
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000159{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000160 if (mFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
161 mFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000162 {
163 return D3DFMT_DXT1;
164 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000165 else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE)
gman@chromium.org50c526d2011-08-10 05:19:44 +0000166 {
167 return D3DFMT_DXT3;
168 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000169 else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE)
gman@chromium.org50c526d2011-08-10 05:19:44 +0000170 {
171 return D3DFMT_DXT5;
172 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000173 else if (mType == GL_FLOAT)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000174 {
175 return D3DFMT_A32B32G32R32F;
176 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000177 else if (mType == GL_HALF_FLOAT_OES)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000178 {
179 return D3DFMT_A16B16G16R16F;
180 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000181 else if (mType == GL_UNSIGNED_BYTE)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000182 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000183 if (mFormat == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000184 {
185 return D3DFMT_L8;
186 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000187 else if (mFormat == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000188 {
189 return D3DFMT_A8L8;
190 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000191 else if (mFormat == GL_RGB)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000192 {
193 return D3DFMT_X8R8G8B8;
194 }
195
196 return D3DFMT_A8R8G8B8;
197 }
198
199 return D3DFMT_A8R8G8B8;
200}
201
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +0000202Texture::Texture(GLuint id) : RefCountObject(id), mSerial(issueSerial())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000203{
204 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
205 mMagFilter = GL_LINEAR;
206 mWrapS = GL_REPEAT;
207 mWrapT = GL_REPEAT;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000208 mDirtyParameters = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000209
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000210 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +0000211
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000212 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000213}
214
215Texture::~Texture()
216{
217}
218
219Blit *Texture::getBlitter()
220{
221 Context *context = getContext();
222 return context->getBlitter();
223}
224
225// Returns true on successful filter state update (valid enum parameter)
226bool Texture::setMinFilter(GLenum filter)
227{
228 switch (filter)
229 {
230 case GL_NEAREST:
231 case GL_LINEAR:
232 case GL_NEAREST_MIPMAP_NEAREST:
233 case GL_LINEAR_MIPMAP_NEAREST:
234 case GL_NEAREST_MIPMAP_LINEAR:
235 case GL_LINEAR_MIPMAP_LINEAR:
236 {
237 if (mMinFilter != filter)
238 {
239 mMinFilter = filter;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000240 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000241 }
242 return true;
243 }
244 default:
245 return false;
246 }
247}
248
249// Returns true on successful filter state update (valid enum parameter)
250bool Texture::setMagFilter(GLenum filter)
251{
252 switch (filter)
253 {
254 case GL_NEAREST:
255 case GL_LINEAR:
256 {
257 if (mMagFilter != filter)
258 {
259 mMagFilter = filter;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000260 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000261 }
262 return true;
263 }
264 default:
265 return false;
266 }
267}
268
269// Returns true on successful wrap state update (valid enum parameter)
270bool Texture::setWrapS(GLenum wrap)
271{
272 switch (wrap)
273 {
274 case GL_REPEAT:
275 case GL_CLAMP_TO_EDGE:
276 case GL_MIRRORED_REPEAT:
277 {
278 if (mWrapS != wrap)
279 {
280 mWrapS = wrap;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000281 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000282 }
283 return true;
284 }
285 default:
286 return false;
287 }
288}
289
290// Returns true on successful wrap state update (valid enum parameter)
291bool Texture::setWrapT(GLenum wrap)
292{
293 switch (wrap)
294 {
295 case GL_REPEAT:
296 case GL_CLAMP_TO_EDGE:
297 case GL_MIRRORED_REPEAT:
298 {
299 if (mWrapT != wrap)
300 {
301 mWrapT = wrap;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000302 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000303 }
304 return true;
305 }
306 default:
307 return false;
308 }
309}
310
311GLenum Texture::getMinFilter() const
312{
313 return mMinFilter;
314}
315
316GLenum Texture::getMagFilter() const
317{
318 return mMagFilter;
319}
320
321GLenum Texture::getWrapS() const
322{
323 return mWrapS;
324}
325
326GLenum Texture::getWrapT() const
327{
328 return mWrapT;
329}
330
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000331// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
332// into the target pixel rectangle at output with outputPitch bytes in between each line.
333void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
334 GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const
335{
336 GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment);
337 input = ((char*)input) - inputPitch * (height - 1);
338
339 switch (type)
340 {
341 case GL_UNSIGNED_BYTE:
342 switch (format)
343 {
344 case GL_ALPHA:
345 loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
346 break;
347 case GL_LUMINANCE:
348 loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);
349 break;
350 case GL_LUMINANCE_ALPHA:
351 loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);
352 break;
353 case GL_RGB:
354 loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
355 break;
356 case GL_RGBA:
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000357 if (supportsSSE2())
358 {
359 loadRGBAUByteImageDataSSE2(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
360 }
361 else
362 {
363 loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
364 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000365 break;
366 case GL_BGRA_EXT:
367 loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
368 break;
369 default: UNREACHABLE();
370 }
371 break;
372 case GL_UNSIGNED_SHORT_5_6_5:
373 switch (format)
374 {
375 case GL_RGB:
376 loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
377 break;
378 default: UNREACHABLE();
379 }
380 break;
381 case GL_UNSIGNED_SHORT_4_4_4_4:
382 switch (format)
383 {
384 case GL_RGBA:
385 loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
386 break;
387 default: UNREACHABLE();
388 }
389 break;
390 case GL_UNSIGNED_SHORT_5_5_5_1:
391 switch (format)
392 {
393 case GL_RGBA:
394 loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
395 break;
396 default: UNREACHABLE();
397 }
398 break;
399 case GL_FLOAT:
400 switch (format)
401 {
402 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
403 case GL_ALPHA:
404 loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
405 break;
406 case GL_LUMINANCE:
407 loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
408 break;
409 case GL_LUMINANCE_ALPHA:
410 loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
411 break;
412 case GL_RGB:
413 loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
414 break;
415 case GL_RGBA:
416 loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
417 break;
418 default: UNREACHABLE();
419 }
420 break;
421 case GL_HALF_FLOAT_OES:
422 switch (format)
423 {
424 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
425 case GL_ALPHA:
426 loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
427 break;
428 case GL_LUMINANCE:
429 loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
430 break;
431 case GL_LUMINANCE_ALPHA:
432 loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
433 break;
434 case GL_RGB:
435 loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
436 break;
437 case GL_RGBA:
438 loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
439 break;
440 default: UNREACHABLE();
441 }
442 break;
443 default: UNREACHABLE();
444 }
445}
446
447void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
448 int inputPitch, const void *input, size_t outputPitch, void *output) const
449{
450 const unsigned char *source = NULL;
451 unsigned char *dest = NULL;
452
453 for (int y = 0; y < height; y++)
454 {
455 source = static_cast<const unsigned char*>(input) + y * inputPitch;
456 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
457 for (int x = 0; x < width; x++)
458 {
459 dest[4 * x + 0] = 0;
460 dest[4 * x + 1] = 0;
461 dest[4 * x + 2] = 0;
462 dest[4 * x + 3] = source[x];
463 }
464 }
465}
466
467void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
468 int inputPitch, const void *input, size_t outputPitch, void *output) const
469{
470 const float *source = NULL;
471 float *dest = NULL;
472
473 for (int y = 0; y < height; y++)
474 {
475 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
476 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
477 for (int x = 0; x < width; x++)
478 {
479 dest[4 * x + 0] = 0;
480 dest[4 * x + 1] = 0;
481 dest[4 * x + 2] = 0;
482 dest[4 * x + 3] = source[x];
483 }
484 }
485}
486
487void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
488 int inputPitch, const void *input, size_t outputPitch, void *output) const
489{
490 const unsigned short *source = NULL;
491 unsigned short *dest = NULL;
492
493 for (int y = 0; y < height; y++)
494 {
495 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
496 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
497 for (int x = 0; x < width; x++)
498 {
499 dest[4 * x + 0] = 0;
500 dest[4 * x + 1] = 0;
501 dest[4 * x + 2] = 0;
502 dest[4 * x + 3] = source[x];
503 }
504 }
505}
506
507void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
508 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
509{
510 const int destBytesPerPixel = native? 1: 4;
511 const unsigned char *source = NULL;
512 unsigned char *dest = NULL;
513
514 for (int y = 0; y < height; y++)
515 {
516 source = static_cast<const unsigned char*>(input) + y * inputPitch;
517 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
518
519 if (!native) // BGRA8 destination format
520 {
521 for (int x = 0; x < width; x++)
522 {
523 dest[4 * x + 0] = source[x];
524 dest[4 * x + 1] = source[x];
525 dest[4 * x + 2] = source[x];
526 dest[4 * x + 3] = 0xFF;
527 }
528 }
529 else // L8 destination format
530 {
531 memcpy(dest, source, width);
532 }
533 }
534}
535
536void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
537 int inputPitch, const void *input, size_t outputPitch, void *output) const
538{
539 const float *source = NULL;
540 float *dest = NULL;
541
542 for (int y = 0; y < height; y++)
543 {
544 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
545 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
546 for (int x = 0; x < width; x++)
547 {
548 dest[4 * x + 0] = source[x];
549 dest[4 * x + 1] = source[x];
550 dest[4 * x + 2] = source[x];
551 dest[4 * x + 3] = 1.0f;
552 }
553 }
554}
555
556void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
557 int inputPitch, const void *input, size_t outputPitch, void *output) const
558{
559 const unsigned short *source = NULL;
560 unsigned short *dest = NULL;
561
562 for (int y = 0; y < height; y++)
563 {
564 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
565 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
566 for (int x = 0; x < width; x++)
567 {
568 dest[4 * x + 0] = source[x];
569 dest[4 * x + 1] = source[x];
570 dest[4 * x + 2] = source[x];
571 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
572 }
573 }
574}
575
576void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
577 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
578{
579 const int destBytesPerPixel = native? 2: 4;
580 const unsigned char *source = NULL;
581 unsigned char *dest = NULL;
582
583 for (int y = 0; y < height; y++)
584 {
585 source = static_cast<const unsigned char*>(input) + y * inputPitch;
586 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
587
588 if (!native) // BGRA8 destination format
589 {
590 for (int x = 0; x < width; x++)
591 {
592 dest[4 * x + 0] = source[2*x+0];
593 dest[4 * x + 1] = source[2*x+0];
594 dest[4 * x + 2] = source[2*x+0];
595 dest[4 * x + 3] = source[2*x+1];
596 }
597 }
598 else
599 {
600 memcpy(dest, source, width * 2);
601 }
602 }
603}
604
605void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
606 int inputPitch, const void *input, size_t outputPitch, void *output) const
607{
608 const float *source = NULL;
609 float *dest = NULL;
610
611 for (int y = 0; y < height; y++)
612 {
613 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
614 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
615 for (int x = 0; x < width; x++)
616 {
617 dest[4 * x + 0] = source[2*x+0];
618 dest[4 * x + 1] = source[2*x+0];
619 dest[4 * x + 2] = source[2*x+0];
620 dest[4 * x + 3] = source[2*x+1];
621 }
622 }
623}
624
625void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
626 int inputPitch, const void *input, size_t outputPitch, void *output) const
627{
628 const unsigned short *source = NULL;
629 unsigned short *dest = NULL;
630
631 for (int y = 0; y < height; y++)
632 {
633 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
634 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
635 for (int x = 0; x < width; x++)
636 {
637 dest[4 * x + 0] = source[2*x+0];
638 dest[4 * x + 1] = source[2*x+0];
639 dest[4 * x + 2] = source[2*x+0];
640 dest[4 * x + 3] = source[2*x+1];
641 }
642 }
643}
644
645void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
646 int inputPitch, const void *input, size_t outputPitch, void *output) const
647{
648 const unsigned char *source = NULL;
649 unsigned char *dest = NULL;
650
651 for (int y = 0; y < height; y++)
652 {
653 source = static_cast<const unsigned char*>(input) + y * inputPitch;
654 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
655 for (int x = 0; x < width; x++)
656 {
657 dest[4 * x + 0] = source[x * 3 + 2];
658 dest[4 * x + 1] = source[x * 3 + 1];
659 dest[4 * x + 2] = source[x * 3 + 0];
660 dest[4 * x + 3] = 0xFF;
661 }
662 }
663}
664
665void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
666 int inputPitch, const void *input, size_t outputPitch, void *output) const
667{
668 const unsigned short *source = NULL;
669 unsigned char *dest = NULL;
670
671 for (int y = 0; y < height; y++)
672 {
673 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
674 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
675 for (int x = 0; x < width; x++)
676 {
677 unsigned short rgba = source[x];
678 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
679 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
680 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
681 dest[4 * x + 3] = 0xFF;
682 }
683 }
684}
685
686void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
687 int inputPitch, const void *input, size_t outputPitch, void *output) const
688{
689 const float *source = NULL;
690 float *dest = NULL;
691
692 for (int y = 0; y < height; y++)
693 {
694 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
695 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
696 for (int x = 0; x < width; x++)
697 {
698 dest[4 * x + 0] = source[x * 3 + 0];
699 dest[4 * x + 1] = source[x * 3 + 1];
700 dest[4 * x + 2] = source[x * 3 + 2];
701 dest[4 * x + 3] = 1.0f;
702 }
703 }
704}
705
706void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
707 int inputPitch, const void *input, size_t outputPitch, void *output) const
708{
709 const unsigned short *source = NULL;
710 unsigned short *dest = NULL;
711
712 for (int y = 0; y < height; y++)
713 {
714 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
715 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
716 for (int x = 0; x < width; x++)
717 {
718 dest[4 * x + 0] = source[x * 3 + 0];
719 dest[4 * x + 1] = source[x * 3 + 1];
720 dest[4 * x + 2] = source[x * 3 + 2];
721 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
722 }
723 }
724}
725
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000726void Texture::loadRGBAUByteImageDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
727 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000728{
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000729 const unsigned int *source = NULL;
730 unsigned int *dest = NULL;
731 __m128i brMask = _mm_set1_epi32(0x00ff00ff);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000732
733 for (int y = 0; y < height; y++)
734 {
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000735 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
736 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
737 int x = 0;
738
739 // Make output writes aligned
740 for (x = 0; ((reinterpret_cast<intptr_t>(&dest[x]) & 15) != 0) && x < width; x++)
741 {
742 unsigned int rgba = source[x];
743 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
744 }
745
746 for (; x + 3 < width; x += 4)
747 {
748 __m128i sourceData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&source[x]));
749 // Mask out g and a, which don't change
750 __m128i gaComponents = _mm_andnot_si128(brMask, sourceData);
751 // Mask out b and r
752 __m128i brComponents = _mm_and_si128(sourceData, brMask);
753 // Swap b and r
754 __m128i brSwapped = _mm_shufflehi_epi16(_mm_shufflelo_epi16(brComponents, _MM_SHUFFLE(2, 3, 0, 1)), _MM_SHUFFLE(2, 3, 0, 1));
755 __m128i result = _mm_or_si128(gaComponents, brSwapped);
756 _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), result);
757 }
758
759 // Perform leftover writes
760 for (; x < width; x++)
761 {
762 unsigned int rgba = source[x];
763 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
764 }
765 }
766}
767
768void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
769 int inputPitch, const void *input, size_t outputPitch, void *output) const
770{
771 const unsigned int *source = NULL;
772 unsigned int *dest = NULL;
773 for (int y = 0; y < height; y++)
774 {
775 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
776 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
777
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000778 for (int x = 0; x < width; x++)
779 {
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000780 unsigned int rgba = source[x];
781 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000782 }
783 }
784}
785
786void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
787 int inputPitch, const void *input, size_t outputPitch, void *output) const
788{
789 const unsigned short *source = NULL;
790 unsigned char *dest = NULL;
791
792 for (int y = 0; y < height; y++)
793 {
794 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
795 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
796 for (int x = 0; x < width; x++)
797 {
798 unsigned short rgba = source[x];
799 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
800 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
801 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
802 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
803 }
804 }
805}
806
807void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
808 int inputPitch, const void *input, size_t outputPitch, void *output) const
809{
810 const unsigned short *source = NULL;
811 unsigned char *dest = NULL;
812
813 for (int y = 0; y < height; y++)
814 {
815 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
816 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
817 for (int x = 0; x < width; x++)
818 {
819 unsigned short rgba = source[x];
820 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
821 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
822 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
823 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
824 }
825 }
826}
827
828void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
829 int inputPitch, const void *input, size_t outputPitch, void *output) const
830{
831 const float *source = NULL;
832 float *dest = NULL;
833
834 for (int y = 0; y < height; y++)
835 {
836 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
837 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
838 memcpy(dest, source, width * 16);
839 }
840}
841
842void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
843 int inputPitch, const void *input, size_t outputPitch, void *output) const
844{
845 const unsigned char *source = NULL;
846 unsigned char *dest = NULL;
847
848 for (int y = 0; y < height; y++)
849 {
850 source = static_cast<const unsigned char*>(input) + y * inputPitch;
851 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
852 memcpy(dest, source, width * 8);
853 }
854}
855
856void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
857 int inputPitch, const void *input, size_t outputPitch, void *output) const
858{
859 const unsigned char *source = NULL;
860 unsigned char *dest = NULL;
861
862 for (int y = 0; y < height; y++)
863 {
864 source = static_cast<const unsigned char*>(input) + y * inputPitch;
865 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
866 memcpy(dest, source, width*4);
867 }
868}
869
870void Texture::loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
gman@chromium.org50c526d2011-08-10 05:19:44 +0000871 int inputPitch, const void *input, size_t outputPitch, void *output) const {
872 switch (getD3DFormat())
873 {
874 case D3DFMT_DXT1:
875 loadDXT1ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
876 break;
877 case D3DFMT_DXT3:
878 loadDXT3ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
879 break;
880 case D3DFMT_DXT5:
881 loadDXT5ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
882 break;
883 }
884}
885
886static void FlipCopyDXT1BlockFull(const unsigned int* source, unsigned int* dest) {
887 // A DXT1 block layout is:
888 // [0-1] color0.
889 // [2-3] color1.
890 // [4-7] color bitmap, 2 bits per pixel.
891 // So each of the 4-7 bytes represents one line, flipping a block is just
892 // flipping those bytes.
893
894 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
895 dest[0] = source[0];
896
897 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
898 dest[1] = (source[1] >> 24) |
899 ((source[1] << 8) & 0x00FF0000) |
900 ((source[1] >> 8) & 0x0000FF00) |
901 (source[1] << 24);
902}
903
904// Flips the first 2 lines of a DXT1 block in the y direction.
905static void FlipCopyDXT1BlockHalf(const unsigned int* source, unsigned int* dest) {
906 // See layout above.
907 dest[0] = source[0];
908 dest[1] = ((source[1] << 8) & 0x0000FF00) |
909 ((source[1] >> 8) & 0x000000FF);
910}
911
912// Flips a full DXT3 block in the y direction.
913static void FlipCopyDXT3BlockFull(const unsigned int* source, unsigned int* dest) {
914 // A DXT3 block layout is:
915 // [0-7] alpha bitmap, 4 bits per pixel.
916 // [8-15] a DXT1 block.
917
918 // First and Second 32 bits are 4bit per pixel alpha and need to be flipped.
919 dest[0] = (source[1] >> 16) | (source[1] << 16);
920 dest[1] = (source[0] >> 16) | (source[0] << 16);
921
922 // And flip the DXT1 block using the above function.
923 FlipCopyDXT1BlockFull(source + 2, dest + 2);
924}
925
926// Flips the first 2 lines of a DXT3 block in the y direction.
927static void FlipCopyDXT3BlockHalf(const unsigned int* source, unsigned int* dest) {
928 // See layout above.
929 dest[0] = (source[1] >> 16) | (source[1] << 16);
930 FlipCopyDXT1BlockHalf(source + 2, dest + 2);
931}
932
933// Flips a full DXT5 block in the y direction.
934static void FlipCopyDXT5BlockFull(const unsigned int* source, unsigned int* dest) {
935 // A DXT5 block layout is:
936 // [0] alpha0.
937 // [1] alpha1.
938 // [2-7] alpha bitmap, 3 bits per pixel.
939 // [8-15] a DXT1 block.
940
941 // The alpha bitmap doesn't easily map lines to bytes, so we have to
942 // interpret it correctly. Extracted from
943 // http://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt :
944 //
945 // The 6 "bits" bytes of the block are decoded into one 48-bit integer:
946 //
947 // bits = bits_0 + 256 * (bits_1 + 256 * (bits_2 + 256 * (bits_3 +
948 // 256 * (bits_4 + 256 * bits_5))))
949 //
950 // bits is a 48-bit unsigned integer, from which a three-bit control code
951 // is extracted for a texel at location (x,y) in the block using:
952 //
953 // code(x,y) = bits[3*(4*y+x)+1..3*(4*y+x)+0]
954 //
955 // where bit 47 is the most significant and bit 0 is the least
956 // significant bit.
957 const unsigned char* sourceBytes = static_cast<const unsigned char*>(static_cast<const void*>(source));
958 unsigned char* destBytes = static_cast<unsigned char*>(static_cast<void*>(dest));
959 unsigned int line_0_1 = sourceBytes[2] + 256 * (sourceBytes[3] + 256 * sourceBytes[4]);
960 unsigned int line_2_3 = sourceBytes[5] + 256 * (sourceBytes[6] + 256 * sourceBytes[7]);
961 // swap lines 0 and 1 in line_0_1.
962 unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) |
963 ((line_0_1 & 0xfff000) >> 12);
964 // swap lines 2 and 3 in line_2_3.
965 unsigned int line_3_2 = ((line_2_3 & 0x000fff) << 12) |
966 ((line_2_3 & 0xfff000) >> 12);
967 destBytes[0] = sourceBytes[0];
968 destBytes[1] = sourceBytes[1];
969 destBytes[2] = line_3_2 & 0xff;
970 destBytes[3] = (line_3_2 & 0xff00) >> 8;
gman@chromium.org2ac3e732011-08-10 07:59:47 +0000971 destBytes[4] = (line_3_2 & 0xff0000) >> 16;
gman@chromium.org50c526d2011-08-10 05:19:44 +0000972 destBytes[5] = line_1_0 & 0xff;
973 destBytes[6] = (line_1_0 & 0xff00) >> 8;
gman@chromium.org2ac3e732011-08-10 07:59:47 +0000974 destBytes[7] = (line_1_0 & 0xff0000) >> 16;
gman@chromium.org50c526d2011-08-10 05:19:44 +0000975
976 // And flip the DXT1 block using the above function.
977 FlipCopyDXT1BlockFull(source + 2, dest + 2);
978}
979
980// Flips the first 2 lines of a DXT5 block in the y direction.
981static void FlipCopyDXT5BlockHalf(const unsigned int* source, unsigned int* dest) {
982 // See layout above.
983 const unsigned char* sourceBytes = static_cast<const unsigned char*>(static_cast<const void*>(source));
984 unsigned char* destBytes = static_cast<unsigned char*>(static_cast<void*>(dest));
985 unsigned int line_0_1 = sourceBytes[2] + 256 * (sourceBytes[3] + 256 * sourceBytes[4]);
986 unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) |
987 ((line_0_1 & 0xfff000) >> 12);
988 destBytes[0] = sourceBytes[0];
989 destBytes[1] = sourceBytes[1];
990 destBytes[2] = line_1_0 & 0xff;
991 destBytes[3] = (line_1_0 & 0xff00) >> 8;
gman@chromium.org25c5cf62011-08-10 08:07:54 +0000992 destBytes[4] = (line_1_0 & 0xff0000) >> 16;
gman@chromium.org50c526d2011-08-10 05:19:44 +0000993 FlipCopyDXT1BlockHalf(source + 2, dest + 2);
994}
995
996void Texture::loadDXT1ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000997 int inputPitch, const void *input, size_t outputPitch, void *output) const
998{
999 ASSERT(xoffset % 4 == 0);
1000 ASSERT(yoffset % 4 == 0);
1001 ASSERT(width % 4 == 0 || width == 2 || width == 1);
1002 ASSERT(inputPitch % 8 == 0);
1003 ASSERT(outputPitch % 8 == 0);
1004
1005 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
1006 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
1007
gman@chromium.org50c526d2011-08-10 05:19:44 +00001008 // Round width up in case it is less than 4.
1009 int blocksAcross = (width + 3) / 4;
1010 int intsAcross = blocksAcross * 2;
1011
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001012 switch (height)
1013 {
1014 case 1:
gman@chromium.org50c526d2011-08-10 05:19:44 +00001015 for (int x = 0; x < intsAcross; x += 2)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001016 {
gman@chromium.org50c526d2011-08-10 05:19:44 +00001017 // just copy the block
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001018 dest[x] = source[x];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001019 dest[x + 1] = source[x + 1];
1020 }
1021 break;
1022 case 2:
gman@chromium.org50c526d2011-08-10 05:19:44 +00001023 for (int x = 0; x < intsAcross; x += 2)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001024 {
gman@chromium.org50c526d2011-08-10 05:19:44 +00001025 FlipCopyDXT1BlockHalf(source + x, dest + x);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001026 }
1027 break;
1028 default:
1029 ASSERT(height % 4 == 0);
1030 for (int y = 0; y < height / 4; ++y)
1031 {
1032 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
1033 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
1034
gman@chromium.org50c526d2011-08-10 05:19:44 +00001035 for (int x = 0; x < intsAcross; x += 2)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001036 {
gman@chromium.org50c526d2011-08-10 05:19:44 +00001037 FlipCopyDXT1BlockFull(source + x, dest + x);
1038 }
1039 }
1040 break;
1041 }
1042}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001043
gman@chromium.org50c526d2011-08-10 05:19:44 +00001044void Texture::loadDXT3ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
1045 int inputPitch, const void *input, size_t outputPitch, void *output) const
1046{
1047 ASSERT(xoffset % 4 == 0);
1048 ASSERT(yoffset % 4 == 0);
1049 ASSERT(width % 4 == 0 || width == 2 || width == 1);
1050 ASSERT(inputPitch % 16 == 0);
1051 ASSERT(outputPitch % 16 == 0);
1052
1053 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
1054 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
1055
1056 // Round width up in case it is less than 4.
1057 int blocksAcross = (width + 3) / 4;
1058 int intsAcross = blocksAcross * 4;
1059
1060 switch (height)
1061 {
1062 case 1:
1063 for (int x = 0; x < intsAcross; x += 4)
1064 {
1065 // just copy the block
1066 dest[x] = source[x];
1067 dest[x + 1] = source[x + 1];
1068 dest[x + 2] = source[x + 2];
1069 dest[x + 3] = source[x + 3];
1070 }
1071 break;
1072 case 2:
1073 for (int x = 0; x < intsAcross; x += 4)
1074 {
1075 FlipCopyDXT3BlockHalf(source + x, dest + x);
1076 }
1077 break;
1078 default:
1079 ASSERT(height % 4 == 0);
1080 for (int y = 0; y < height / 4; ++y)
1081 {
1082 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
1083 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
1084
1085 for (int x = 0; x < intsAcross; x += 4)
1086 {
1087 FlipCopyDXT3BlockFull(source + x, dest + x);
1088 }
1089 }
1090 break;
1091 }
1092}
1093
1094void Texture::loadDXT5ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
1095 int inputPitch, const void *input, size_t outputPitch, void *output) const
1096{
1097 ASSERT(xoffset % 4 == 0);
1098 ASSERT(yoffset % 4 == 0);
1099 ASSERT(width % 4 == 0 || width == 2 || width == 1);
1100 ASSERT(inputPitch % 16 == 0);
1101 ASSERT(outputPitch % 16 == 0);
1102
1103 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
1104 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
1105
1106 // Round width up in case it is less than 4.
1107 int blocksAcross = (width + 3) / 4;
1108 int intsAcross = blocksAcross * 4;
1109
1110 switch (height)
1111 {
1112 case 1:
1113 for (int x = 0; x < intsAcross; x += 4)
1114 {
1115 // just copy the block
1116 dest[x] = source[x];
1117 dest[x + 1] = source[x + 1];
1118 dest[x + 2] = source[x + 2];
1119 dest[x + 3] = source[x + 3];
1120 }
1121 break;
1122 case 2:
1123 for (int x = 0; x < intsAcross; x += 4)
1124 {
1125 FlipCopyDXT5BlockHalf(source + x, dest + x);
1126 }
1127 break;
1128 default:
1129 ASSERT(height % 4 == 0);
gman@chromium.org2ac3e732011-08-10 07:59:47 +00001130 for (int y = 0; y < height / 4; ++y)
gman@chromium.org50c526d2011-08-10 05:19:44 +00001131 {
1132 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
1133 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
1134
1135 for (int x = 0; x < intsAcross; x += 4)
1136 {
1137 FlipCopyDXT5BlockFull(source + x, dest + x);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001138 }
1139 }
1140 break;
1141 }
1142}
1143
daniel@transgaming.com61208202011-03-21 16:38:50 +00001144void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001145{
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00001146 image->createSurface();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001147
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001148 if (pixels != NULL && image->getSurface() != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001149 {
1150 D3DSURFACE_DESC description;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001151 image->getSurface()->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001152
1153 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001154 HRESULT result = image->lock(&locked, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001155
1156 if (SUCCEEDED(result))
1157 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001158 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 +00001159 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001160 }
1161
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001162 image->markDirty();
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001163 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001164 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001165}
1166
daniel@transgaming.com61208202011-03-21 16:38:50 +00001167void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001168{
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00001169 image->createSurface();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001170
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001171 if (pixels != NULL && image->getSurface() != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001172 {
1173 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001174 HRESULT result = image->lock(&locked, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001175
1176 if (SUCCEEDED(result))
1177 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001178 int inputPitch = ComputeCompressedPitch(image->getWidth(), image->getFormat());
1179 int inputSize = ComputeCompressedSize(image->getWidth(), image->getHeight(), image->getFormat());
1180 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 +00001181 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001182 }
1183
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001184 image->markDirty();
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001185 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001186 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001187}
1188
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001189bool 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 +00001190{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001191 if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001192 {
1193 error(GL_INVALID_VALUE);
1194 return false;
1195 }
1196
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001197 if (IsCompressed(image->getFormat()))
jbauman@chromium.orge2f954c2011-05-03 20:45:27 +00001198 {
1199 error(GL_INVALID_OPERATION);
1200 return false;
1201 }
1202
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001203 if (format != image->getFormat())
jbauman@chromium.orge2f954c2011-05-03 20:45:27 +00001204 {
1205 error(GL_INVALID_OPERATION);
1206 return false;
1207 }
1208
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00001209 image->createSurface();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001210
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001211 if (pixels != NULL && image->getSurface() != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001212 {
1213 D3DSURFACE_DESC description;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001214 image->getSurface()->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001215
1216 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001217 HRESULT result = image->lock(&locked, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001218
1219 if (SUCCEEDED(result))
1220 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001221 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 +00001222 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001223 }
1224
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001225 image->markDirty();
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001226 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001227 }
1228
1229 return true;
1230}
1231
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001232bool 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 +00001233{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001234 if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001235 {
1236 error(GL_INVALID_VALUE);
1237 return false;
1238 }
1239
1240 if (format != getInternalFormat())
1241 {
1242 error(GL_INVALID_OPERATION);
1243 return false;
1244 }
1245
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001246 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001247 {
1248 RECT updateRegion;
1249 updateRegion.left = xoffset;
1250 updateRegion.right = xoffset + width;
1251 updateRegion.bottom = yoffset + height;
1252 updateRegion.top = yoffset;
1253
1254 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001255 HRESULT result = image->lock(&locked, &updateRegion);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001256
1257 if (SUCCEEDED(result))
1258 {
1259 int inputPitch = ComputeCompressedPitch(width, format);
1260 int inputSize = ComputeCompressedSize(width, height, format);
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001261 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 +00001262 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001263 }
1264
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001265 image->markDirty();
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001266 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001267 }
1268
1269 return true;
1270}
1271
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001272// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
1273void 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 +00001274{
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00001275 image->createSurface();
1276
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001277 if (!image->getSurface())
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001278 {
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00001279 ERR("Failed to create an image surface.");
1280 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001281 }
1282
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001283 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001284 IDirect3DSurface9 *renderTargetData = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001285 D3DSURFACE_DESC description;
1286 renderTarget->GetDesc(&description);
1287
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001288 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001289
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001290 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001291 {
1292 ERR("Could not create matching destination surface.");
1293 return error(GL_OUT_OF_MEMORY);
1294 }
1295
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001296 result = device->GetRenderTargetData(renderTarget, renderTargetData);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001297
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001298 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001299 {
1300 ERR("GetRenderTargetData unexpectedly failed.");
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001301 renderTargetData->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001302 return error(GL_OUT_OF_MEMORY);
1303 }
1304
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001305 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001306 int destYOffset = transformPixelYOffset(yoffset, height, image->getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001307 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001308
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001309 if (image->isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001310 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001311 result = D3DXLoadSurfaceFromSurface(image->getSurface(), NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0);
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001312
1313 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001314 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001315 ERR("Copying surfaces unexpectedly failed.");
1316 renderTargetData->Release();
1317 return error(GL_OUT_OF_MEMORY);
1318 }
1319 }
1320 else
1321 {
1322 D3DLOCKED_RECT sourceLock = {0};
1323 result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001324
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001325 if (FAILED(result))
1326 {
1327 ERR("Failed to lock the source surface (rectangle might be invalid).");
1328 renderTargetData->Release();
1329 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001330 }
1331
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001332 D3DLOCKED_RECT destLock = {0};
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001333 result = image->lock(&destLock, &destRect);
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001334
1335 if (FAILED(result))
1336 {
1337 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1338 renderTargetData->UnlockRect();
1339 renderTargetData->Release();
1340 return error(GL_OUT_OF_MEMORY);
1341 }
1342
1343 if (destLock.pBits && sourceLock.pBits)
1344 {
1345 unsigned char *source = (unsigned char*)sourceLock.pBits;
1346 unsigned char *dest = (unsigned char*)destLock.pBits;
1347
1348 switch (description.Format)
1349 {
1350 case D3DFMT_X8R8G8B8:
1351 case D3DFMT_A8R8G8B8:
1352 switch(image->getD3DFormat())
1353 {
1354 case D3DFMT_L8:
1355 for(int y = 0; y < height; y++)
1356 {
1357 for(int x = 0; x < width; x++)
1358 {
1359 dest[x] = source[x * 4 + 2];
1360 }
1361
1362 source += sourceLock.Pitch;
1363 dest += destLock.Pitch;
1364 }
1365 break;
1366 case D3DFMT_A8L8:
1367 for(int y = 0; y < height; y++)
1368 {
1369 for(int x = 0; x < width; x++)
1370 {
1371 dest[x * 2 + 0] = source[x * 4 + 2];
1372 dest[x * 2 + 1] = source[x * 4 + 3];
1373 }
1374
1375 source += sourceLock.Pitch;
1376 dest += destLock.Pitch;
1377 }
1378 break;
1379 default:
1380 UNREACHABLE();
1381 }
1382 break;
1383 case D3DFMT_R5G6B5:
1384 switch(image->getD3DFormat())
1385 {
1386 case D3DFMT_L8:
1387 for(int y = 0; y < height; y++)
1388 {
1389 for(int x = 0; x < width; x++)
1390 {
1391 unsigned char red = source[x * 2 + 1] & 0xF8;
1392 dest[x] = red | (red >> 5);
1393 }
1394
1395 source += sourceLock.Pitch;
1396 dest += destLock.Pitch;
1397 }
1398 break;
1399 default:
1400 UNREACHABLE();
1401 }
1402 break;
1403 case D3DFMT_A1R5G5B5:
1404 switch(image->getD3DFormat())
1405 {
1406 case D3DFMT_L8:
1407 for(int y = 0; y < height; y++)
1408 {
1409 for(int x = 0; x < width; x++)
1410 {
1411 unsigned char red = source[x * 2 + 1] & 0x7C;
1412 dest[x] = (red << 1) | (red >> 4);
1413 }
1414
1415 source += sourceLock.Pitch;
1416 dest += destLock.Pitch;
1417 }
1418 break;
1419 case D3DFMT_A8L8:
1420 for(int y = 0; y < height; y++)
1421 {
1422 for(int x = 0; x < width; x++)
1423 {
1424 unsigned char red = source[x * 2 + 1] & 0x7C;
1425 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1426 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1427 }
1428
1429 source += sourceLock.Pitch;
1430 dest += destLock.Pitch;
1431 }
1432 break;
1433 default:
1434 UNREACHABLE();
1435 }
1436 break;
1437 default:
1438 UNREACHABLE();
1439 }
1440 }
1441
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001442 image->unlock();
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001443 renderTargetData->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001444 }
1445
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001446 renderTargetData->Release();
1447
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001448 image->markDirty();
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001449 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001450}
1451
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001452IDirect3DBaseTexture9 *Texture::getTexture()
1453{
1454 if (!isComplete())
1455 {
1456 return NULL;
1457 }
1458
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001459 if (!getBaseTexture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001460 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001461 createTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001462 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001463
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +00001464 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001465
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001466 return getBaseTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001467}
1468
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001469bool Texture::hasDirtyParameters() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001470{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001471 return mDirtyParameters;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001472}
1473
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001474bool Texture::hasDirtyImages() const
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001475{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001476 return mDirtyImages;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001477}
1478
1479void Texture::resetDirty()
1480{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001481 mDirtyParameters = false;
1482 mDirtyImages = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001483}
1484
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001485unsigned int Texture::getSerial() const
1486{
1487 return mSerial;
1488}
1489
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001490GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1491{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001492 if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001493 {
1494 return maxlevel;
1495 }
1496 else
1497 {
1498 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1499 return 1;
1500 }
1501}
1502
1503GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1504{
1505 return creationLevels(size, size, maxlevel);
1506}
1507
1508int Texture::levelCount() const
1509{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001510 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001511}
1512
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001513unsigned int Texture::issueSerial()
1514{
1515 return mCurrentSerial++;
1516}
1517
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001518Texture2D::Texture2D(GLuint id) : Texture(id)
1519{
1520 mTexture = NULL;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001521 mSurface = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001522}
1523
1524Texture2D::~Texture2D()
1525{
1526 mColorbufferProxy.set(NULL);
1527
1528 if (mTexture)
1529 {
1530 mTexture->Release();
1531 mTexture = NULL;
1532 }
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001533
1534 if (mSurface)
1535 {
1536 mSurface->setBoundTexture(NULL);
1537 mSurface = NULL;
1538 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001539}
1540
1541GLenum Texture2D::getTarget() const
1542{
1543 return GL_TEXTURE_2D;
1544}
1545
daniel@transgaming.com61208202011-03-21 16:38:50 +00001546GLsizei Texture2D::getWidth() const
1547{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001548 return mImageArray[0].getWidth();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001549}
1550
1551GLsizei Texture2D::getHeight() const
1552{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001553 return mImageArray[0].getHeight();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001554}
1555
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001556GLenum Texture2D::getInternalFormat() const
1557{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001558 return mImageArray[0].getFormat();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001559}
1560
daniel@transgaming.com61208202011-03-21 16:38:50 +00001561GLenum Texture2D::getType() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001562{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001563 return mImageArray[0].getType();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001564}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001565
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001566D3DFORMAT Texture2D::getD3DFormat() const
1567{
1568 return mImageArray[0].getD3DFormat();
1569}
1570
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001571void Texture2D::redefineImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type, bool forceRedefine)
daniel@transgaming.com61208202011-03-21 16:38:50 +00001572{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001573 GLsizei textureWidth = mImageArray[0].getWidth();
1574 GLsizei textureHeight = mImageArray[0].getHeight();
1575 GLenum textureFormat = mImageArray[0].getFormat();
1576 GLenum textureType = mImageArray[0].getType();
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001577
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001578 mImageArray[level].redefine(format, width, height, type);
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00001579
daniel@transgaming.com61208202011-03-21 16:38:50 +00001580 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001581 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001582 return;
1583 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001584
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001585 bool widthOkay = (textureWidth >> level == width) || (textureWidth >> level == 0 && width == 1);
1586 bool heightOkay = (textureHeight >> level == height) || (textureHeight >> level == 0 && height == 1);
1587 bool textureOkay = (widthOkay && heightOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00001588
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00001589 if (!textureOkay || forceRedefine || mSurface)
daniel@transgaming.com61208202011-03-21 16:38:50 +00001590 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001591 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1592 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001593 mImageArray[i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001594 }
1595
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001596 mTexture->Release();
1597 mTexture = NULL;
1598 mDirtyImages = true;
1599 mIsRenderable = false;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001600
1601 if (mSurface)
1602 {
1603 mSurface->setBoundTexture(NULL);
1604 mSurface = NULL;
1605 }
apatrick@chromium.org57a2cd62011-06-08 00:04:07 +00001606
1607 mColorbufferProxy.set(NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001608 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001609}
1610
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001611void 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 +00001612{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001613 redefineImage(level, format, width, height, type, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001614
daniel@transgaming.com61208202011-03-21 16:38:50 +00001615 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001616}
1617
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001618void Texture2D::bindTexImage(egl::Surface *surface)
1619{
1620 GLenum format;
1621
1622 switch(surface->getFormat())
1623 {
1624 case D3DFMT_A8R8G8B8:
1625 format = GL_RGBA;
1626 break;
1627 case D3DFMT_X8R8G8B8:
1628 format = GL_RGB;
1629 break;
1630 default:
1631 UNIMPLEMENTED();
1632 return;
1633 }
1634
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001635 redefineImage(0, format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE, true);
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001636
1637 IDirect3DTexture9 *texture = surface->getOffscreenTexture();
1638
1639 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001640 mDirtyImages = true;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001641 mIsRenderable = true;
1642 mSurface = surface;
1643 mSurface->setBoundTexture(this);
1644}
1645
1646void Texture2D::releaseTexImage()
1647{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001648 redefineImage(0, GL_RGB, 0, 0, GL_UNSIGNED_BYTE, true);
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001649}
1650
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001651void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001652{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001653 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001654
daniel@transgaming.com61208202011-03-21 16:38:50 +00001655 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001656}
1657
1658void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1659{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001660 ASSERT(mImageArray[level].getSurface() != NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001661
1662 if (level < levelCount())
1663 {
1664 IDirect3DSurface9 *destLevel = NULL;
1665 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1666
1667 ASSERT(SUCCEEDED(result));
1668
1669 if (SUCCEEDED(result))
1670 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001671 Image *image = &mImageArray[level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001672
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001673 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->getHeight());;
daniel@transgaming.comb612f882011-11-09 17:44:31 +00001674 POINT destPoint = {sourceRect.left, sourceRect.top};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001675
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001676 result = getDevice()->UpdateSurface(image->getSurface(), &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001677 ASSERT(SUCCEEDED(result));
1678
1679 destLevel->Release();
1680
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001681 image->markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001682 }
1683 }
1684}
1685
1686void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1687{
1688 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1689 {
1690 commitRect(level, xoffset, yoffset, width, height);
1691 }
1692}
1693
1694void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1695{
1696 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1697 {
1698 commitRect(level, xoffset, yoffset, width, height);
1699 }
1700}
1701
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001702void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001703{
1704 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1705
1706 if (!renderTarget)
1707 {
1708 ERR("Failed to retrieve the render target.");
1709 return error(GL_OUT_OF_MEMORY);
1710 }
1711
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001712 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001713
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001714 if (!mImageArray[level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001715 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001716 copyToImage(&mImageArray[level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001717 }
1718 else
1719 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001720 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001721 {
1722 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001723 }
daniel@transgaming.com3b3c1d42011-06-08 20:38:09 +00001724
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001725 mImageArray[level].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001726
1727 if (width != 0 && height != 0 && level < levelCount())
1728 {
1729 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1730 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1731 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1732 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1733 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001734
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001735 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[level].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001736
1737 IDirect3DSurface9 *dest;
1738 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1739
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001740 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001741 dest->Release();
1742 }
1743 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001744}
1745
1746void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1747{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001748 if (xoffset + width > mImageArray[level].getWidth() || yoffset + height > mImageArray[level].getHeight())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001749 {
1750 return error(GL_INVALID_VALUE);
1751 }
1752
1753 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1754
1755 if (!renderTarget)
1756 {
1757 ERR("Failed to retrieve the render target.");
1758 return error(GL_OUT_OF_MEMORY);
1759 }
1760
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001761 if (!mImageArray[level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001762 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001763 copyToImage(&mImageArray[level], xoffset, yoffset, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001764 }
1765 else
1766 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001767 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001768 {
1769 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001770 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001771
1772 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001773
1774 if (level < levelCount())
1775 {
1776 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1777 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1778 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1779 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1780 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1781
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001782 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001783
1784 IDirect3DSurface9 *dest;
1785 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1786
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001787 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0].getFormat(), xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001788 dest->Release();
1789 }
1790 }
1791}
1792
1793// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1794bool Texture2D::isComplete() const
1795{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001796 GLsizei width = mImageArray[0].getWidth();
1797 GLsizei height = mImageArray[0].getHeight();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001798
1799 if (width <= 0 || height <= 0)
1800 {
1801 return false;
1802 }
1803
1804 bool mipmapping = false;
1805
1806 switch (mMinFilter)
1807 {
1808 case GL_NEAREST:
1809 case GL_LINEAR:
1810 mipmapping = false;
1811 break;
1812 case GL_NEAREST_MIPMAP_NEAREST:
1813 case GL_LINEAR_MIPMAP_NEAREST:
1814 case GL_NEAREST_MIPMAP_LINEAR:
1815 case GL_LINEAR_MIPMAP_LINEAR:
1816 mipmapping = true;
1817 break;
1818 default: UNREACHABLE();
1819 }
1820
1821 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1822 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1823 {
1824 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1825 {
1826 return false;
1827 }
1828 }
1829
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001830 bool npot = getContext()->supportsNonPower2Texture();
1831
1832 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001833 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001834 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
1835 (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1836 {
1837 return false;
1838 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001839 }
1840
1841 if (mipmapping)
1842 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001843 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001844 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001845 if (!isPow2(width) || !isPow2(height))
1846 {
1847 return false;
1848 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001849 }
1850
1851 int q = log2(std::max(width, height));
1852
1853 for (int level = 1; level <= q; level++)
1854 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001855 if (mImageArray[level].getFormat() != mImageArray[0].getFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001856 {
1857 return false;
1858 }
1859
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001860 if (mImageArray[level].getType() != mImageArray[0].getType())
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001861 {
1862 return false;
1863 }
1864
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001865 if (mImageArray[level].getWidth() != std::max(1, width >> level))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001866 {
1867 return false;
1868 }
1869
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001870 if (mImageArray[level].getHeight() != std::max(1, height >> level))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001871 {
1872 return false;
1873 }
1874 }
1875 }
1876
1877 return true;
1878}
1879
1880bool Texture2D::isCompressed() const
1881{
1882 return IsCompressed(getInternalFormat());
1883}
1884
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001885IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1886{
1887 return mTexture;
1888}
1889
1890// Constructs a Direct3D 9 texture resource from the texture images
1891void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001892{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001893 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001894 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001895 GLint levels = creationLevels(mImageArray[0].getWidth(), mImageArray[0].getHeight(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001896
daniel@transgaming.com61208202011-03-21 16:38:50 +00001897 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001898 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 +00001899
1900 if (FAILED(result))
1901 {
1902 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001903 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001904 }
1905
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001906 if (mTexture)
1907 {
1908 mTexture->Release();
1909 }
1910
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001911 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001912 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001913 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001914}
1915
1916void Texture2D::updateTexture()
1917{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001918 int levels = levelCount();
1919
1920 for (int level = 0; level < levels; level++)
1921 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00001922 Image *image = &mImageArray[level];
1923
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001924 if (image->isDirty())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001925 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001926 commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001927 }
1928 }
1929}
1930
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001931void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001932{
1933 IDirect3DTexture9 *texture = NULL;
1934
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001935 if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001936 {
1937 egl::Display *display = getDisplay();
1938 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001939 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001940 GLint levels = creationLevels(mImageArray[0].getWidth(), mImageArray[0].getHeight(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001941
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001942 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 +00001943
1944 if (FAILED(result))
1945 {
1946 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001947 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001948 }
1949
1950 if (mTexture != NULL)
1951 {
1952 int levels = levelCount();
1953 for (int i = 0; i < levels; i++)
1954 {
1955 IDirect3DSurface9 *source;
1956 result = mTexture->GetSurfaceLevel(i, &source);
1957
1958 if (FAILED(result))
1959 {
1960 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1961
1962 texture->Release();
1963
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001964 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001965 }
1966
1967 IDirect3DSurface9 *dest;
1968 result = texture->GetSurfaceLevel(i, &dest);
1969
1970 if (FAILED(result))
1971 {
1972 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1973
1974 texture->Release();
1975 source->Release();
1976
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001977 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001978 }
1979
1980 display->endScene();
1981 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1982
1983 if (FAILED(result))
1984 {
1985 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1986
1987 texture->Release();
1988 source->Release();
1989 dest->Release();
1990
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001991 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001992 }
1993
1994 source->Release();
1995 dest->Release();
1996 }
1997 }
1998 }
1999
2000 if (mTexture != NULL)
2001 {
2002 mTexture->Release();
2003 }
2004
2005 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002006 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002007 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002008}
2009
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002010void Texture2D::generateMipmaps()
2011{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002012 if (!getContext()->supportsNonPower2Texture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002013 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002014 if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight()))
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002015 {
2016 return error(GL_INVALID_OPERATION);
2017 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002018 }
2019
2020 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002021 unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight()));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002022 for (unsigned int i = 1; i <= q; i++)
2023 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002024 mImageArray[i].redefine(mImageArray[0].getFormat(),
2025 std::max(mImageArray[0].getWidth() >> i, 1),
2026 std::max(mImageArray[0].getHeight() >> i, 1),
2027 mImageArray[0].getType());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002028 }
2029
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002030 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002031 {
2032 if (mTexture == NULL)
2033 {
2034 ERR(" failed because mTexture was null.");
2035 return;
2036 }
2037
2038 for (unsigned int i = 1; i <= q; i++)
2039 {
2040 IDirect3DSurface9 *upper = NULL;
2041 IDirect3DSurface9 *lower = NULL;
2042
2043 mTexture->GetSurfaceLevel(i-1, &upper);
2044 mTexture->GetSurfaceLevel(i, &lower);
2045
2046 if (upper != NULL && lower != NULL)
2047 {
2048 getBlitter()->boxFilter(upper, lower);
2049 }
2050
2051 if (upper != NULL) upper->Release();
2052 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002053
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002054 mImageArray[i].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002055 }
2056 }
2057 else
2058 {
2059 for (unsigned int i = 1; i <= q; i++)
2060 {
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00002061 mImageArray[i].createSurface();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002062
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002063 if (mImageArray[i].getSurface() == NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002064 {
2065 return error(GL_OUT_OF_MEMORY);
2066 }
2067
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002068 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 +00002069 {
2070 ERR(" failed to load filter %d to %d.", i - 1, i);
2071 }
2072
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002073 mImageArray[i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002074 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002075 }
2076}
2077
2078Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
2079{
2080 if (target != GL_TEXTURE_2D)
2081 {
2082 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2083 }
2084
2085 if (mColorbufferProxy.get() == NULL)
2086 {
2087 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2088 }
2089
2090 return mColorbufferProxy.get();
2091}
2092
2093IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
2094{
2095 ASSERT(target == GL_TEXTURE_2D);
2096
daniel@transgaming.com61208202011-03-21 16:38:50 +00002097 if (!mIsRenderable)
2098 {
2099 convertToRenderTarget();
2100 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002101
2102 if (mTexture == NULL)
2103 {
2104 return NULL;
2105 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002106
2107 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002108
2109 IDirect3DSurface9 *renderTarget = NULL;
2110 mTexture->GetSurfaceLevel(0, &renderTarget);
2111
2112 return renderTarget;
2113}
2114
2115TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
2116{
2117 mTexture = NULL;
2118}
2119
2120TextureCubeMap::~TextureCubeMap()
2121{
2122 for (int i = 0; i < 6; i++)
2123 {
2124 mFaceProxies[i].set(NULL);
2125 }
2126
2127 if (mTexture)
2128 {
2129 mTexture->Release();
2130 mTexture = NULL;
2131 }
2132}
2133
2134GLenum TextureCubeMap::getTarget() const
2135{
2136 return GL_TEXTURE_CUBE_MAP;
2137}
2138
daniel@transgaming.com61208202011-03-21 16:38:50 +00002139GLsizei TextureCubeMap::getWidth() const
2140{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002141 return mImageArray[0][0].getWidth();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002142}
2143
2144GLsizei TextureCubeMap::getHeight() const
2145{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002146 return mImageArray[0][0].getHeight();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002147}
2148
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002149GLenum TextureCubeMap::getInternalFormat() const
2150{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002151 return mImageArray[0][0].getFormat();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002152}
2153
daniel@transgaming.com61208202011-03-21 16:38:50 +00002154GLenum TextureCubeMap::getType() const
2155{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002156 return mImageArray[0][0].getType();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002157}
2158
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002159D3DFORMAT TextureCubeMap::getD3DFormat() const
2160{
2161 return mImageArray[0][0].getD3DFormat();
2162}
2163
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002164void 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 +00002165{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002166 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002167}
2168
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002169void 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 +00002170{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002171 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002172}
2173
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002174void 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 +00002175{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002176 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002177}
2178
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002179void 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 +00002180{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002181 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002182}
2183
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002184void 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 +00002185{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002186 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002187}
2188
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002189void 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 +00002190{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002191 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002192}
2193
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002194void 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 +00002195{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002196 redefineImage(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002197
daniel@transgaming.com61208202011-03-21 16:38:50 +00002198 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002199}
2200
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002201void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002202{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002203 ASSERT(mImageArray[face][level].getSurface() != NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002204
2205 if (level < levelCount())
2206 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002207 IDirect3DSurface9 *destLevel = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002208 ASSERT(destLevel != NULL);
2209
2210 if (destLevel != NULL)
2211 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002212 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002213
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002214 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->getHeight());;
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002215 POINT destPoint = {sourceRect.left, sourceRect.top};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002216
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002217 HRESULT result = getDevice()->UpdateSurface(image->getSurface(), &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002218 ASSERT(SUCCEEDED(result));
2219
2220 destLevel->Release();
2221
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002222 image->markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002223 }
2224 }
2225}
2226
2227void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2228{
2229 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
2230 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002231 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002232 }
2233}
2234
2235void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
2236{
2237 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
2238 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002239 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002240 }
2241}
2242
2243// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
2244bool TextureCubeMap::isComplete() const
2245{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002246 int size = mImageArray[0][0].getWidth();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002247
2248 if (size <= 0)
2249 {
2250 return false;
2251 }
2252
2253 bool mipmapping;
2254
2255 switch (mMinFilter)
2256 {
2257 case GL_NEAREST:
2258 case GL_LINEAR:
2259 mipmapping = false;
2260 break;
2261 case GL_NEAREST_MIPMAP_NEAREST:
2262 case GL_LINEAR_MIPMAP_NEAREST:
2263 case GL_NEAREST_MIPMAP_LINEAR:
2264 case GL_LINEAR_MIPMAP_LINEAR:
2265 mipmapping = true;
2266 break;
2267 default: UNREACHABLE();
2268 }
2269
2270 for (int face = 0; face < 6; face++)
2271 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002272 if (mImageArray[face][0].getWidth() != size || mImageArray[face][0].getHeight() != size)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002273 {
2274 return false;
2275 }
2276 }
2277
2278 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
2279 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
2280 {
2281 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
2282 {
2283 return false;
2284 }
2285 }
2286
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002287 bool npot = getContext()->supportsNonPower2Texture();
2288
2289 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002290 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002291 if ((getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE) && !isPow2(size))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002292 {
2293 return false;
2294 }
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002295 }
2296
2297 if (mipmapping)
2298 {
2299 if (!npot)
2300 {
2301 if (!isPow2(size))
2302 {
2303 return false;
2304 }
2305 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002306
2307 int q = log2(size);
2308
2309 for (int face = 0; face < 6; face++)
2310 {
2311 for (int level = 1; level <= q; level++)
2312 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002313 if (mImageArray[face][level].getFormat() != mImageArray[0][0].getFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002314 {
2315 return false;
2316 }
2317
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002318 if (mImageArray[face][level].getType() != mImageArray[0][0].getType())
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002319 {
2320 return false;
2321 }
2322
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002323 if (mImageArray[face][level].getWidth() != std::max(1, size >> level))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002324 {
2325 return false;
2326 }
2327
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002328 ASSERT(mImageArray[face][level].getHeight() == mImageArray[face][level].getWidth());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002329 }
2330 }
2331 }
2332
2333 return true;
2334}
2335
2336bool TextureCubeMap::isCompressed() const
2337{
2338 return IsCompressed(getInternalFormat());
2339}
2340
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002341IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
2342{
2343 return mTexture;
2344}
2345
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002346// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002347void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002348{
2349 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002350 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002351 GLint levels = creationLevels(mImageArray[0][0].getWidth(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002352
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002353 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002354 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].getWidth(), levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002355
2356 if (FAILED(result))
2357 {
2358 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002359 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002360 }
2361
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002362 if (mTexture)
2363 {
2364 mTexture->Release();
2365 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002366
2367 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002368 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002369 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002370}
2371
2372void TextureCubeMap::updateTexture()
2373{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002374 for (int face = 0; face < 6; face++)
2375 {
2376 int levels = levelCount();
2377 for (int level = 0; level < levels; level++)
2378 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002379 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002380
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00002381 if (image->isDirty())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002382 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002383 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002384 }
2385 }
2386 }
2387}
2388
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002389void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002390{
2391 IDirect3DCubeTexture9 *texture = NULL;
2392
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002393 if (mImageArray[0][0].getWidth() != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002394 {
2395 egl::Display *display = getDisplay();
2396 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002397 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002398 GLint levels = creationLevels(mImageArray[0][0].getWidth(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002399
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002400 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].getWidth(), levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002401
2402 if (FAILED(result))
2403 {
2404 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002405 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002406 }
2407
2408 if (mTexture != NULL)
2409 {
2410 int levels = levelCount();
2411 for (int f = 0; f < 6; f++)
2412 {
2413 for (int i = 0; i < levels; i++)
2414 {
2415 IDirect3DSurface9 *source;
2416 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2417
2418 if (FAILED(result))
2419 {
2420 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2421
2422 texture->Release();
2423
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002424 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002425 }
2426
2427 IDirect3DSurface9 *dest;
2428 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2429
2430 if (FAILED(result))
2431 {
2432 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2433
2434 texture->Release();
2435 source->Release();
2436
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002437 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002438 }
2439
2440 display->endScene();
2441 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2442
2443 if (FAILED(result))
2444 {
2445 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2446
2447 texture->Release();
2448 source->Release();
2449 dest->Release();
2450
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002451 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002452 }
daniel@transgaming.coma1a86202011-08-09 13:41:08 +00002453
2454 source->Release();
2455 dest->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002456 }
2457 }
2458 }
2459 }
2460
2461 if (mTexture != NULL)
2462 {
2463 mTexture->Release();
2464 }
2465
2466 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002467 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002468 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002469}
2470
daniel@transgaming.com61208202011-03-21 16:38:50 +00002471void 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 +00002472{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002473 redefineImage(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002474
daniel@transgaming.com61208202011-03-21 16:38:50 +00002475 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002476}
2477
2478unsigned int TextureCubeMap::faceIndex(GLenum face)
2479{
2480 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2481 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2482 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2483 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2484 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2485
2486 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2487}
2488
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002489void TextureCubeMap::redefineImage(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002490{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002491 GLsizei textureWidth = mImageArray[0][0].getWidth();
2492 GLsizei textureHeight = mImageArray[0][0].getHeight();
2493 GLenum textureFormat = mImageArray[0][0].getFormat();
2494 GLenum textureType = mImageArray[0][0].getType();
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002495
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002496 mImageArray[face][level].redefine(format, width, height, type);
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00002497
daniel@transgaming.com61208202011-03-21 16:38:50 +00002498 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002499 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002500 return;
2501 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002502
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002503 bool sizeOkay = (textureWidth >> level == width);
2504 bool textureOkay = (sizeOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002505
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00002506 if (!textureOkay)
daniel@transgaming.com61208202011-03-21 16:38:50 +00002507 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002508 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2509 {
2510 for (int f = 0; f < 6; f++)
2511 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002512 mImageArray[f][i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002513 }
2514 }
2515
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002516 mTexture->Release();
2517 mTexture = NULL;
2518 mDirtyImages = true;
2519 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002520 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002521}
2522
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002523void 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 +00002524{
2525 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2526
2527 if (!renderTarget)
2528 {
2529 ERR("Failed to retrieve the render target.");
2530 return error(GL_OUT_OF_MEMORY);
2531 }
2532
2533 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002534 redefineImage(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002535
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002536 if (!mImageArray[faceindex][level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002537 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002538 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002539 }
2540 else
2541 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002542 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002543 {
2544 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002545 }
daniel@transgaming.com3b3c1d42011-06-08 20:38:09 +00002546
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002547 mImageArray[faceindex][level].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002548
2549 ASSERT(width == height);
2550
2551 if (width > 0 && level < levelCount())
2552 {
2553 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2554 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2555 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2556 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2557 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2558
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002559 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[faceindex][level].getWidth());
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002560
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002561 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2562
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002563 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002564 dest->Release();
2565 }
2566 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002567}
2568
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002569IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum target, unsigned int level)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002570{
2571 if (mTexture == NULL)
2572 {
2573 UNREACHABLE();
2574 return NULL;
2575 }
2576
2577 IDirect3DSurface9 *surface = NULL;
2578
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002579 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), level, &surface);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002580
2581 return (SUCCEEDED(hr)) ? surface : NULL;
2582}
2583
2584void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2585{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002586 GLsizei size = mImageArray[faceIndex(target)][level].getWidth();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002587
2588 if (xoffset + width > size || yoffset + height > size)
2589 {
2590 return error(GL_INVALID_VALUE);
2591 }
2592
2593 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2594
2595 if (!renderTarget)
2596 {
2597 ERR("Failed to retrieve the render target.");
2598 return error(GL_OUT_OF_MEMORY);
2599 }
2600
2601 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com01dae852011-11-09 17:44:53 +00002602
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002603 if (!mImageArray[faceindex][level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002604 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002605 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002606 }
2607 else
2608 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002609 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002610 {
2611 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002612 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002613
2614 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002615
2616 if (level < levelCount())
2617 {
2618 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2619 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2620 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2621 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2622 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2623
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002624 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].getWidth());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002625
2626 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2627
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002628 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0][0].getFormat(), xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002629 dest->Release();
2630 }
2631 }
2632}
2633
2634bool TextureCubeMap::isCubeComplete() const
2635{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002636 if (mImageArray[0][0].getWidth() == 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002637 {
2638 return false;
2639 }
2640
2641 for (unsigned int f = 1; f < 6; f++)
2642 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002643 if (mImageArray[f][0].getWidth() != mImageArray[0][0].getWidth()
2644 || mImageArray[f][0].getFormat() != mImageArray[0][0].getFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002645 {
2646 return false;
2647 }
2648 }
2649
2650 return true;
2651}
2652
2653void TextureCubeMap::generateMipmaps()
2654{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002655 if (!isCubeComplete())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002656 {
2657 return error(GL_INVALID_OPERATION);
2658 }
2659
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002660 if (!getContext()->supportsNonPower2Texture())
2661 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002662 if (!isPow2(mImageArray[0][0].getWidth()))
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002663 {
2664 return error(GL_INVALID_OPERATION);
2665 }
2666 }
2667
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002668 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002669 unsigned int q = log2(mImageArray[0][0].getWidth());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002670 for (unsigned int f = 0; f < 6; f++)
2671 {
2672 for (unsigned int i = 1; i <= q; i++)
2673 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002674 mImageArray[f][i].redefine(mImageArray[f][0].getFormat(),
2675 std::max(mImageArray[f][0].getWidth() >> i, 1),
2676 std::max(mImageArray[f][0].getWidth() >> i, 1),
2677 mImageArray[f][0].getType());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002678 }
2679 }
2680
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002681 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002682 {
2683 if (mTexture == NULL)
2684 {
2685 return;
2686 }
2687
2688 for (unsigned int f = 0; f < 6; f++)
2689 {
2690 for (unsigned int i = 1; i <= q; i++)
2691 {
2692 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2693 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2694
2695 if (upper != NULL && lower != NULL)
2696 {
2697 getBlitter()->boxFilter(upper, lower);
2698 }
2699
2700 if (upper != NULL) upper->Release();
2701 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002702
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002703 mImageArray[f][i].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002704 }
2705 }
2706 }
2707 else
2708 {
2709 for (unsigned int f = 0; f < 6; f++)
2710 {
2711 for (unsigned int i = 1; i <= q; i++)
2712 {
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00002713 mImageArray[f][i].createSurface();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002714 if (mImageArray[f][i].getSurface() == NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002715 {
2716 return error(GL_OUT_OF_MEMORY);
2717 }
2718
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002719 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 +00002720 {
2721 ERR(" failed to load filter %d to %d.", i - 1, i);
2722 }
2723
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002724 mImageArray[f][i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002725 }
2726 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002727 }
2728}
2729
2730Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2731{
2732 if (!IsCubemapTextureTarget(target))
2733 {
2734 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2735 }
2736
2737 unsigned int face = faceIndex(target);
2738
2739 if (mFaceProxies[face].get() == NULL)
2740 {
2741 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2742 }
2743
2744 return mFaceProxies[face].get();
2745}
2746
2747IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2748{
2749 ASSERT(IsCubemapTextureTarget(target));
2750
daniel@transgaming.com61208202011-03-21 16:38:50 +00002751 if (!mIsRenderable)
2752 {
2753 convertToRenderTarget();
2754 }
2755
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002756 if (mTexture == NULL)
2757 {
2758 return NULL;
2759 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002760
2761 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002762
2763 IDirect3DSurface9 *renderTarget = NULL;
2764 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2765
2766 return renderTarget;
2767}
2768
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002769}