blob: a4330ca5525deb5a73586a94aa4c0008fb9c3c3f [file] [log] [blame]
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Texture.cpp: Implements the gl::Texture class and its derived classes
8// Texture2D and TextureCubeMap. Implements GL texture objects and related
9// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
10
11#include "libGLESv2/Texture.h"
12
13#include <d3dx9tex.h>
14
15#include <algorithm>
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +000016#include <intrin.h>
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000017
18#include "common/debug.h"
19
jbauman@chromium.orgae345802011-03-30 22:04:25 +000020#include "libEGL/Display.h"
21
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000022#include "libGLESv2/main.h"
23#include "libGLESv2/mathutil.h"
24#include "libGLESv2/utilities.h"
25#include "libGLESv2/Blit.h"
26#include "libGLESv2/Framebuffer.h"
27
28namespace gl
29{
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +000030unsigned int Texture::mCurrentSerial = 1;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000031
daniel@transgaming.comde631782011-11-09 17:45:04 +000032Image::Image()
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000033 : mWidth(0), mHeight(0), mDirty(false), mSurface(NULL), mFormat(GL_NONE), mType(GL_UNSIGNED_BYTE)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000034{
35}
36
daniel@transgaming.comde631782011-11-09 17:45:04 +000037Image::~Image()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000038{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000039 if (mSurface)
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +000040 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000041 mSurface->Release();
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +000042 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000043}
44
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000045void Image::redefine(GLenum format, GLsizei width, GLsizei height, GLenum type)
46{
daniel@transgaming.com4c0a7712011-11-09 17:45:19 +000047 if (mWidth != width ||
48 mHeight != height ||
49 mFormat != format ||
50 mType != type)
51 {
52 if (mSurface)
53 {
54 mSurface->Release();
55 mSurface = NULL;
56 }
57 }
58
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000059 mWidth = width;
60 mHeight = height;
61 mFormat = format;
62 mType = type;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000063}
64
65void Image::createSurface()
66{
67 if(mSurface)
68 {
69 return;
70 }
71
72 IDirect3DTexture9 *newTexture = NULL;
73 IDirect3DSurface9 *newSurface = NULL;
74
75 if (mWidth != 0 && mHeight != 0)
76 {
77 int levelToFetch = 0;
78 GLsizei requestWidth = mWidth;
79 GLsizei requestHeight = mHeight;
80 if (IsCompressed(mFormat) && (mWidth % 4 != 0 || mHeight % 4 != 0))
81 {
82 bool isMult4 = false;
83 int upsampleCount = 0;
84 while (!isMult4)
85 {
86 requestWidth <<= 1;
87 requestHeight <<= 1;
88 upsampleCount++;
89 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
90 {
91 isMult4 = true;
92 }
93 }
94 levelToFetch = upsampleCount;
95 }
96
97 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, getD3DFormat(),
98 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
99
100 if (FAILED(result))
101 {
102 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com73de05a2011-11-09 17:45:24 +0000103 ERR("Creating image surface failed.");
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000104 return error(GL_OUT_OF_MEMORY);
105 }
106
107 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
108 newTexture->Release();
109 }
110
111 mSurface = newSurface;
112}
113
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +0000114HRESULT Image::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect)
115{
116 createSurface();
117
118 HRESULT result = D3DERR_INVALIDCALL;
119
120 if (mSurface)
121 {
122 result = mSurface->LockRect(lockedRect, rect, 0);
123 ASSERT(SUCCEEDED(result));
124
125 mDirty = true;
126 }
127
128 return result;
129}
130
131void Image::unlock()
132{
133 if (mSurface)
134 {
135 HRESULT result = mSurface->UnlockRect();
136 ASSERT(SUCCEEDED(result));
137 }
138}
139
daniel@transgaming.comde631782011-11-09 17:45:04 +0000140bool Image::isRenderable() const
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000141{
142 switch(getD3DFormat())
143 {
144 case D3DFMT_L8:
145 case D3DFMT_A8L8:
146 case D3DFMT_DXT1:
gman@chromium.org50c526d2011-08-10 05:19:44 +0000147 case D3DFMT_DXT3:
148 case D3DFMT_DXT5:
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000149 return false;
150 case D3DFMT_A8R8G8B8:
151 case D3DFMT_X8R8G8B8:
152 case D3DFMT_A16B16G16R16F:
153 case D3DFMT_A32B32G32R32F:
154 return true;
155 default:
156 UNREACHABLE();
157 }
158
159 return false;
160}
161
daniel@transgaming.comde631782011-11-09 17:45:04 +0000162D3DFORMAT Image::getD3DFormat() const
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000163{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000164 if (mFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
165 mFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000166 {
167 return D3DFMT_DXT1;
168 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000169 else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE)
gman@chromium.org50c526d2011-08-10 05:19:44 +0000170 {
171 return D3DFMT_DXT3;
172 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000173 else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE)
gman@chromium.org50c526d2011-08-10 05:19:44 +0000174 {
175 return D3DFMT_DXT5;
176 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000177 else if (mType == GL_FLOAT)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000178 {
179 return D3DFMT_A32B32G32R32F;
180 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000181 else if (mType == GL_HALF_FLOAT_OES)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000182 {
183 return D3DFMT_A16B16G16R16F;
184 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000185 else if (mType == GL_UNSIGNED_BYTE)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000186 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000187 if (mFormat == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000188 {
189 return D3DFMT_L8;
190 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000191 else if (mFormat == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000192 {
193 return D3DFMT_A8L8;
194 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000195 else if (mFormat == GL_RGB)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000196 {
197 return D3DFMT_X8R8G8B8;
198 }
199
200 return D3DFMT_A8R8G8B8;
201 }
202
203 return D3DFMT_A8R8G8B8;
204}
205
daniel@transgaming.com73de05a2011-11-09 17:45:24 +0000206IDirect3DSurface9 *Image::getSurface()
207{
208 createSurface();
209
210 return mSurface;
211}
212
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000213// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
214// into the target pixel rectangle at output with outputPitch bytes in between each line.
215void Image::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
216 GLint unpackAlignment, const void *input, size_t outputPitch, void *output) const
217{
218 GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment);
219 input = ((char*)input) - inputPitch * (height - 1);
220
221 switch (type)
222 {
223 case GL_UNSIGNED_BYTE:
224 switch (format)
225 {
226 case GL_ALPHA:
227 loadAlphaData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
228 break;
229 case GL_LUMINANCE:
230 loadLuminanceData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, getD3DFormat() == D3DFMT_L8);
231 break;
232 case GL_LUMINANCE_ALPHA:
233 loadLuminanceAlphaData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, getD3DFormat() == D3DFMT_A8L8);
234 break;
235 case GL_RGB:
236 loadRGBUByteData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
237 break;
238 case GL_RGBA:
239 if (supportsSSE2())
240 {
241 loadRGBAUByteDataSSE2(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
242 }
243 else
244 {
245 loadRGBAUByteData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
246 }
247 break;
248 case GL_BGRA_EXT:
249 loadBGRAData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
250 break;
251 default: UNREACHABLE();
252 }
253 break;
254 case GL_UNSIGNED_SHORT_5_6_5:
255 switch (format)
256 {
257 case GL_RGB:
258 loadRGB565Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
259 break;
260 default: UNREACHABLE();
261 }
262 break;
263 case GL_UNSIGNED_SHORT_4_4_4_4:
264 switch (format)
265 {
266 case GL_RGBA:
267 loadRGBA4444Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
268 break;
269 default: UNREACHABLE();
270 }
271 break;
272 case GL_UNSIGNED_SHORT_5_5_5_1:
273 switch (format)
274 {
275 case GL_RGBA:
276 loadRGBA5551Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
277 break;
278 default: UNREACHABLE();
279 }
280 break;
281 case GL_FLOAT:
282 switch (format)
283 {
284 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
285 case GL_ALPHA:
286 loadAlphaFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
287 break;
288 case GL_LUMINANCE:
289 loadLuminanceFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
290 break;
291 case GL_LUMINANCE_ALPHA:
292 loadLuminanceAlphaFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
293 break;
294 case GL_RGB:
295 loadRGBFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
296 break;
297 case GL_RGBA:
298 loadRGBAFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
299 break;
300 default: UNREACHABLE();
301 }
302 break;
303 case GL_HALF_FLOAT_OES:
304 switch (format)
305 {
306 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
307 case GL_ALPHA:
308 loadAlphaHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
309 break;
310 case GL_LUMINANCE:
311 loadLuminanceHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
312 break;
313 case GL_LUMINANCE_ALPHA:
314 loadLuminanceAlphaHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
315 break;
316 case GL_RGB:
317 loadRGBHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
318 break;
319 case GL_RGBA:
320 loadRGBAHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
321 break;
322 default: UNREACHABLE();
323 }
324 break;
325 default: UNREACHABLE();
326 }
327}
328
329void Image::loadAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
330 int inputPitch, const void *input, size_t outputPitch, void *output) const
331{
332 const unsigned char *source = NULL;
333 unsigned char *dest = NULL;
334
335 for (int y = 0; y < height; y++)
336 {
337 source = static_cast<const unsigned char*>(input) + y * inputPitch;
338 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
339 for (int x = 0; x < width; x++)
340 {
341 dest[4 * x + 0] = 0;
342 dest[4 * x + 1] = 0;
343 dest[4 * x + 2] = 0;
344 dest[4 * x + 3] = source[x];
345 }
346 }
347}
348
349void Image::loadAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
350 int inputPitch, const void *input, size_t outputPitch, void *output) const
351{
352 const float *source = NULL;
353 float *dest = NULL;
354
355 for (int y = 0; y < height; y++)
356 {
357 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
358 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
359 for (int x = 0; x < width; x++)
360 {
361 dest[4 * x + 0] = 0;
362 dest[4 * x + 1] = 0;
363 dest[4 * x + 2] = 0;
364 dest[4 * x + 3] = source[x];
365 }
366 }
367}
368
369void Image::loadAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
370 int inputPitch, const void *input, size_t outputPitch, void *output) const
371{
372 const unsigned short *source = NULL;
373 unsigned short *dest = NULL;
374
375 for (int y = 0; y < height; y++)
376 {
377 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
378 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
379 for (int x = 0; x < width; x++)
380 {
381 dest[4 * x + 0] = 0;
382 dest[4 * x + 1] = 0;
383 dest[4 * x + 2] = 0;
384 dest[4 * x + 3] = source[x];
385 }
386 }
387}
388
389void Image::loadLuminanceData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
390 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
391{
392 const int destBytesPerPixel = native? 1: 4;
393 const unsigned char *source = NULL;
394 unsigned char *dest = NULL;
395
396 for (int y = 0; y < height; y++)
397 {
398 source = static_cast<const unsigned char*>(input) + y * inputPitch;
399 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
400
401 if (!native) // BGRA8 destination format
402 {
403 for (int x = 0; x < width; x++)
404 {
405 dest[4 * x + 0] = source[x];
406 dest[4 * x + 1] = source[x];
407 dest[4 * x + 2] = source[x];
408 dest[4 * x + 3] = 0xFF;
409 }
410 }
411 else // L8 destination format
412 {
413 memcpy(dest, source, width);
414 }
415 }
416}
417
418void Image::loadLuminanceFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
419 int inputPitch, const void *input, size_t outputPitch, void *output) const
420{
421 const float *source = NULL;
422 float *dest = NULL;
423
424 for (int y = 0; y < height; y++)
425 {
426 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
427 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
428 for (int x = 0; x < width; x++)
429 {
430 dest[4 * x + 0] = source[x];
431 dest[4 * x + 1] = source[x];
432 dest[4 * x + 2] = source[x];
433 dest[4 * x + 3] = 1.0f;
434 }
435 }
436}
437
438void Image::loadLuminanceHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
439 int inputPitch, const void *input, size_t outputPitch, void *output) const
440{
441 const unsigned short *source = NULL;
442 unsigned short *dest = NULL;
443
444 for (int y = 0; y < height; y++)
445 {
446 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
447 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
448 for (int x = 0; x < width; x++)
449 {
450 dest[4 * x + 0] = source[x];
451 dest[4 * x + 1] = source[x];
452 dest[4 * x + 2] = source[x];
453 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
454 }
455 }
456}
457
458void Image::loadLuminanceAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
459 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
460{
461 const int destBytesPerPixel = native? 2: 4;
462 const unsigned char *source = NULL;
463 unsigned char *dest = NULL;
464
465 for (int y = 0; y < height; y++)
466 {
467 source = static_cast<const unsigned char*>(input) + y * inputPitch;
468 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
469
470 if (!native) // BGRA8 destination format
471 {
472 for (int x = 0; x < width; x++)
473 {
474 dest[4 * x + 0] = source[2*x+0];
475 dest[4 * x + 1] = source[2*x+0];
476 dest[4 * x + 2] = source[2*x+0];
477 dest[4 * x + 3] = source[2*x+1];
478 }
479 }
480 else
481 {
482 memcpy(dest, source, width * 2);
483 }
484 }
485}
486
487void Image::loadLuminanceAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
488 int inputPitch, const void *input, size_t outputPitch, void *output) const
489{
490 const float *source = NULL;
491 float *dest = NULL;
492
493 for (int y = 0; y < height; y++)
494 {
495 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
496 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
497 for (int x = 0; x < width; x++)
498 {
499 dest[4 * x + 0] = source[2*x+0];
500 dest[4 * x + 1] = source[2*x+0];
501 dest[4 * x + 2] = source[2*x+0];
502 dest[4 * x + 3] = source[2*x+1];
503 }
504 }
505}
506
507void Image::loadLuminanceAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
508 int inputPitch, const void *input, size_t outputPitch, void *output) const
509{
510 const unsigned short *source = NULL;
511 unsigned short *dest = NULL;
512
513 for (int y = 0; y < height; y++)
514 {
515 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
516 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
517 for (int x = 0; x < width; x++)
518 {
519 dest[4 * x + 0] = source[2*x+0];
520 dest[4 * x + 1] = source[2*x+0];
521 dest[4 * x + 2] = source[2*x+0];
522 dest[4 * x + 3] = source[2*x+1];
523 }
524 }
525}
526
527void Image::loadRGBUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
528 int inputPitch, const void *input, size_t outputPitch, void *output) const
529{
530 const unsigned char *source = NULL;
531 unsigned char *dest = NULL;
532
533 for (int y = 0; y < height; y++)
534 {
535 source = static_cast<const unsigned char*>(input) + y * inputPitch;
536 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
537 for (int x = 0; x < width; x++)
538 {
539 dest[4 * x + 0] = source[x * 3 + 2];
540 dest[4 * x + 1] = source[x * 3 + 1];
541 dest[4 * x + 2] = source[x * 3 + 0];
542 dest[4 * x + 3] = 0xFF;
543 }
544 }
545}
546
547void Image::loadRGB565Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
548 int inputPitch, const void *input, size_t outputPitch, void *output) const
549{
550 const unsigned short *source = NULL;
551 unsigned char *dest = NULL;
552
553 for (int y = 0; y < height; y++)
554 {
555 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
556 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
557 for (int x = 0; x < width; x++)
558 {
559 unsigned short rgba = source[x];
560 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
561 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
562 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
563 dest[4 * x + 3] = 0xFF;
564 }
565 }
566}
567
568void Image::loadRGBFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
569 int inputPitch, const void *input, size_t outputPitch, void *output) const
570{
571 const float *source = NULL;
572 float *dest = NULL;
573
574 for (int y = 0; y < height; y++)
575 {
576 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
577 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
578 for (int x = 0; x < width; x++)
579 {
580 dest[4 * x + 0] = source[x * 3 + 0];
581 dest[4 * x + 1] = source[x * 3 + 1];
582 dest[4 * x + 2] = source[x * 3 + 2];
583 dest[4 * x + 3] = 1.0f;
584 }
585 }
586}
587
588void Image::loadRGBHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
589 int inputPitch, const void *input, size_t outputPitch, void *output) const
590{
591 const unsigned short *source = NULL;
592 unsigned short *dest = NULL;
593
594 for (int y = 0; y < height; y++)
595 {
596 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
597 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
598 for (int x = 0; x < width; x++)
599 {
600 dest[4 * x + 0] = source[x * 3 + 0];
601 dest[4 * x + 1] = source[x * 3 + 1];
602 dest[4 * x + 2] = source[x * 3 + 2];
603 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
604 }
605 }
606}
607
608void Image::loadRGBAUByteDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
609 int inputPitch, const void *input, size_t outputPitch, void *output) const
610{
611 const unsigned int *source = NULL;
612 unsigned int *dest = NULL;
613 __m128i brMask = _mm_set1_epi32(0x00ff00ff);
614
615 for (int y = 0; y < height; y++)
616 {
617 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
618 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
619 int x = 0;
620
621 // Make output writes aligned
622 for (x = 0; ((reinterpret_cast<intptr_t>(&dest[x]) & 15) != 0) && x < width; x++)
623 {
624 unsigned int rgba = source[x];
625 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
626 }
627
628 for (; x + 3 < width; x += 4)
629 {
630 __m128i sourceData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&source[x]));
631 // Mask out g and a, which don't change
632 __m128i gaComponents = _mm_andnot_si128(brMask, sourceData);
633 // Mask out b and r
634 __m128i brComponents = _mm_and_si128(sourceData, brMask);
635 // Swap b and r
636 __m128i brSwapped = _mm_shufflehi_epi16(_mm_shufflelo_epi16(brComponents, _MM_SHUFFLE(2, 3, 0, 1)), _MM_SHUFFLE(2, 3, 0, 1));
637 __m128i result = _mm_or_si128(gaComponents, brSwapped);
638 _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), result);
639 }
640
641 // Perform leftover writes
642 for (; x < width; x++)
643 {
644 unsigned int rgba = source[x];
645 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
646 }
647 }
648}
649
650void Image::loadRGBAUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
651 int inputPitch, const void *input, size_t outputPitch, void *output) const
652{
653 const unsigned int *source = NULL;
654 unsigned int *dest = NULL;
655 for (int y = 0; y < height; y++)
656 {
657 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
658 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
659
660 for (int x = 0; x < width; x++)
661 {
662 unsigned int rgba = source[x];
663 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
664 }
665 }
666}
667
668void Image::loadRGBA4444Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
669 int inputPitch, const void *input, size_t outputPitch, void *output) const
670{
671 const unsigned short *source = NULL;
672 unsigned char *dest = NULL;
673
674 for (int y = 0; y < height; y++)
675 {
676 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
677 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
678 for (int x = 0; x < width; x++)
679 {
680 unsigned short rgba = source[x];
681 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
682 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
683 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
684 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
685 }
686 }
687}
688
689void Image::loadRGBA5551Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
690 int inputPitch, const void *input, size_t outputPitch, void *output) const
691{
692 const unsigned short *source = NULL;
693 unsigned char *dest = NULL;
694
695 for (int y = 0; y < height; y++)
696 {
697 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
698 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
699 for (int x = 0; x < width; x++)
700 {
701 unsigned short rgba = source[x];
702 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
703 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
704 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
705 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
706 }
707 }
708}
709
710void Image::loadRGBAFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
711 int inputPitch, const void *input, size_t outputPitch, void *output) const
712{
713 const float *source = NULL;
714 float *dest = NULL;
715
716 for (int y = 0; y < height; y++)
717 {
718 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
719 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
720 memcpy(dest, source, width * 16);
721 }
722}
723
724void Image::loadRGBAHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
725 int inputPitch, const void *input, size_t outputPitch, void *output) const
726{
727 const unsigned char *source = NULL;
728 unsigned char *dest = NULL;
729
730 for (int y = 0; y < height; y++)
731 {
732 source = static_cast<const unsigned char*>(input) + y * inputPitch;
733 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
734 memcpy(dest, source, width * 8);
735 }
736}
737
738void Image::loadBGRAData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
739 int inputPitch, const void *input, size_t outputPitch, void *output) const
740{
741 const unsigned char *source = NULL;
742 unsigned char *dest = NULL;
743
744 for (int y = 0; y < height; y++)
745 {
746 source = static_cast<const unsigned char*>(input) + y * inputPitch;
747 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
748 memcpy(dest, source, width*4);
749 }
750}
751
752void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
753 int inputPitch, const void *input, size_t outputPitch, void *output) const {
754 switch (getD3DFormat())
755 {
756 case D3DFMT_DXT1:
757 loadDXT1Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
758 break;
759 case D3DFMT_DXT3:
760 loadDXT3Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
761 break;
762 case D3DFMT_DXT5:
763 loadDXT5Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
764 break;
765 }
766}
767
768static void FlipCopyDXT1BlockFull(const unsigned int* source, unsigned int* dest) {
769 // A DXT1 block layout is:
770 // [0-1] color0.
771 // [2-3] color1.
772 // [4-7] color bitmap, 2 bits per pixel.
773 // So each of the 4-7 bytes represents one line, flipping a block is just
774 // flipping those bytes.
775
776 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
777 dest[0] = source[0];
778
779 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
780 dest[1] = (source[1] >> 24) |
781 ((source[1] << 8) & 0x00FF0000) |
782 ((source[1] >> 8) & 0x0000FF00) |
783 (source[1] << 24);
784}
785
786// Flips the first 2 lines of a DXT1 block in the y direction.
787static void FlipCopyDXT1BlockHalf(const unsigned int* source, unsigned int* dest) {
788 // See layout above.
789 dest[0] = source[0];
790 dest[1] = ((source[1] << 8) & 0x0000FF00) |
791 ((source[1] >> 8) & 0x000000FF);
792}
793
794// Flips a full DXT3 block in the y direction.
795static void FlipCopyDXT3BlockFull(const unsigned int* source, unsigned int* dest) {
796 // A DXT3 block layout is:
797 // [0-7] alpha bitmap, 4 bits per pixel.
798 // [8-15] a DXT1 block.
799
800 // First and Second 32 bits are 4bit per pixel alpha and need to be flipped.
801 dest[0] = (source[1] >> 16) | (source[1] << 16);
802 dest[1] = (source[0] >> 16) | (source[0] << 16);
803
804 // And flip the DXT1 block using the above function.
805 FlipCopyDXT1BlockFull(source + 2, dest + 2);
806}
807
808// Flips the first 2 lines of a DXT3 block in the y direction.
809static void FlipCopyDXT3BlockHalf(const unsigned int* source, unsigned int* dest) {
810 // See layout above.
811 dest[0] = (source[1] >> 16) | (source[1] << 16);
812 FlipCopyDXT1BlockHalf(source + 2, dest + 2);
813}
814
815// Flips a full DXT5 block in the y direction.
816static void FlipCopyDXT5BlockFull(const unsigned int* source, unsigned int* dest) {
817 // A DXT5 block layout is:
818 // [0] alpha0.
819 // [1] alpha1.
820 // [2-7] alpha bitmap, 3 bits per pixel.
821 // [8-15] a DXT1 block.
822
823 // The alpha bitmap doesn't easily map lines to bytes, so we have to
824 // interpret it correctly. Extracted from
825 // http://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt :
826 //
827 // The 6 "bits" bytes of the block are decoded into one 48-bit integer:
828 //
829 // bits = bits_0 + 256 * (bits_1 + 256 * (bits_2 + 256 * (bits_3 +
830 // 256 * (bits_4 + 256 * bits_5))))
831 //
832 // bits is a 48-bit unsigned integer, from which a three-bit control code
833 // is extracted for a texel at location (x,y) in the block using:
834 //
835 // code(x,y) = bits[3*(4*y+x)+1..3*(4*y+x)+0]
836 //
837 // where bit 47 is the most significant and bit 0 is the least
838 // significant bit.
839 const unsigned char* sourceBytes = static_cast<const unsigned char*>(static_cast<const void*>(source));
840 unsigned char* destBytes = static_cast<unsigned char*>(static_cast<void*>(dest));
841 unsigned int line_0_1 = sourceBytes[2] + 256 * (sourceBytes[3] + 256 * sourceBytes[4]);
842 unsigned int line_2_3 = sourceBytes[5] + 256 * (sourceBytes[6] + 256 * sourceBytes[7]);
843 // swap lines 0 and 1 in line_0_1.
844 unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) |
845 ((line_0_1 & 0xfff000) >> 12);
846 // swap lines 2 and 3 in line_2_3.
847 unsigned int line_3_2 = ((line_2_3 & 0x000fff) << 12) |
848 ((line_2_3 & 0xfff000) >> 12);
849 destBytes[0] = sourceBytes[0];
850 destBytes[1] = sourceBytes[1];
851 destBytes[2] = line_3_2 & 0xff;
852 destBytes[3] = (line_3_2 & 0xff00) >> 8;
853 destBytes[4] = (line_3_2 & 0xff0000) >> 16;
854 destBytes[5] = line_1_0 & 0xff;
855 destBytes[6] = (line_1_0 & 0xff00) >> 8;
856 destBytes[7] = (line_1_0 & 0xff0000) >> 16;
857
858 // And flip the DXT1 block using the above function.
859 FlipCopyDXT1BlockFull(source + 2, dest + 2);
860}
861
862// Flips the first 2 lines of a DXT5 block in the y direction.
863static void FlipCopyDXT5BlockHalf(const unsigned int* source, unsigned int* dest) {
864 // See layout above.
865 const unsigned char* sourceBytes = static_cast<const unsigned char*>(static_cast<const void*>(source));
866 unsigned char* destBytes = static_cast<unsigned char*>(static_cast<void*>(dest));
867 unsigned int line_0_1 = sourceBytes[2] + 256 * (sourceBytes[3] + 256 * sourceBytes[4]);
868 unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) |
869 ((line_0_1 & 0xfff000) >> 12);
870 destBytes[0] = sourceBytes[0];
871 destBytes[1] = sourceBytes[1];
872 destBytes[2] = line_1_0 & 0xff;
873 destBytes[3] = (line_1_0 & 0xff00) >> 8;
874 destBytes[4] = (line_1_0 & 0xff0000) >> 16;
875 FlipCopyDXT1BlockHalf(source + 2, dest + 2);
876}
877
878void Image::loadDXT1Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
879 int inputPitch, const void *input, size_t outputPitch, void *output) const
880{
881 ASSERT(xoffset % 4 == 0);
882 ASSERT(yoffset % 4 == 0);
883 ASSERT(width % 4 == 0 || width == 2 || width == 1);
884 ASSERT(inputPitch % 8 == 0);
885 ASSERT(outputPitch % 8 == 0);
886
887 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
888 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
889
890 // Round width up in case it is less than 4.
891 int blocksAcross = (width + 3) / 4;
892 int intsAcross = blocksAcross * 2;
893
894 switch (height)
895 {
896 case 1:
897 for (int x = 0; x < intsAcross; x += 2)
898 {
899 // just copy the block
900 dest[x] = source[x];
901 dest[x + 1] = source[x + 1];
902 }
903 break;
904 case 2:
905 for (int x = 0; x < intsAcross; x += 2)
906 {
907 FlipCopyDXT1BlockHalf(source + x, dest + x);
908 }
909 break;
910 default:
911 ASSERT(height % 4 == 0);
912 for (int y = 0; y < height / 4; ++y)
913 {
914 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
915 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
916
917 for (int x = 0; x < intsAcross; x += 2)
918 {
919 FlipCopyDXT1BlockFull(source + x, dest + x);
920 }
921 }
922 break;
923 }
924}
925
926void Image::loadDXT3Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
927 int inputPitch, const void *input, size_t outputPitch, void *output) const
928{
929 ASSERT(xoffset % 4 == 0);
930 ASSERT(yoffset % 4 == 0);
931 ASSERT(width % 4 == 0 || width == 2 || width == 1);
932 ASSERT(inputPitch % 16 == 0);
933 ASSERT(outputPitch % 16 == 0);
934
935 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
936 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
937
938 // Round width up in case it is less than 4.
939 int blocksAcross = (width + 3) / 4;
940 int intsAcross = blocksAcross * 4;
941
942 switch (height)
943 {
944 case 1:
945 for (int x = 0; x < intsAcross; x += 4)
946 {
947 // just copy the block
948 dest[x] = source[x];
949 dest[x + 1] = source[x + 1];
950 dest[x + 2] = source[x + 2];
951 dest[x + 3] = source[x + 3];
952 }
953 break;
954 case 2:
955 for (int x = 0; x < intsAcross; x += 4)
956 {
957 FlipCopyDXT3BlockHalf(source + x, dest + x);
958 }
959 break;
960 default:
961 ASSERT(height % 4 == 0);
962 for (int y = 0; y < height / 4; ++y)
963 {
964 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
965 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
966
967 for (int x = 0; x < intsAcross; x += 4)
968 {
969 FlipCopyDXT3BlockFull(source + x, dest + x);
970 }
971 }
972 break;
973 }
974}
975
976void Image::loadDXT5Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
977 int inputPitch, const void *input, size_t outputPitch, void *output) const
978{
979 ASSERT(xoffset % 4 == 0);
980 ASSERT(yoffset % 4 == 0);
981 ASSERT(width % 4 == 0 || width == 2 || width == 1);
982 ASSERT(inputPitch % 16 == 0);
983 ASSERT(outputPitch % 16 == 0);
984
985 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
986 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
987
988 // Round width up in case it is less than 4.
989 int blocksAcross = (width + 3) / 4;
990 int intsAcross = blocksAcross * 4;
991
992 switch (height)
993 {
994 case 1:
995 for (int x = 0; x < intsAcross; x += 4)
996 {
997 // just copy the block
998 dest[x] = source[x];
999 dest[x + 1] = source[x + 1];
1000 dest[x + 2] = source[x + 2];
1001 dest[x + 3] = source[x + 3];
1002 }
1003 break;
1004 case 2:
1005 for (int x = 0; x < intsAcross; x += 4)
1006 {
1007 FlipCopyDXT5BlockHalf(source + x, dest + x);
1008 }
1009 break;
1010 default:
1011 ASSERT(height % 4 == 0);
1012 for (int y = 0; y < height / 4; ++y)
1013 {
1014 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
1015 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
1016
1017 for (int x = 0; x < intsAcross; x += 4)
1018 {
1019 FlipCopyDXT5BlockFull(source + x, dest + x);
1020 }
1021 }
1022 break;
1023 }
1024}
1025
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001026Texture::Texture(GLuint id) : RefCountObject(id), mSerial(issueSerial())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001027{
1028 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
1029 mMagFilter = GL_LINEAR;
1030 mWrapS = GL_REPEAT;
1031 mWrapT = GL_REPEAT;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001032 mDirtyParameters = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001033
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001034 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001035
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001036 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001037}
1038
1039Texture::~Texture()
1040{
1041}
1042
1043Blit *Texture::getBlitter()
1044{
1045 Context *context = getContext();
1046 return context->getBlitter();
1047}
1048
1049// Returns true on successful filter state update (valid enum parameter)
1050bool Texture::setMinFilter(GLenum filter)
1051{
1052 switch (filter)
1053 {
1054 case GL_NEAREST:
1055 case GL_LINEAR:
1056 case GL_NEAREST_MIPMAP_NEAREST:
1057 case GL_LINEAR_MIPMAP_NEAREST:
1058 case GL_NEAREST_MIPMAP_LINEAR:
1059 case GL_LINEAR_MIPMAP_LINEAR:
1060 {
1061 if (mMinFilter != filter)
1062 {
1063 mMinFilter = filter;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001064 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001065 }
1066 return true;
1067 }
1068 default:
1069 return false;
1070 }
1071}
1072
1073// Returns true on successful filter state update (valid enum parameter)
1074bool Texture::setMagFilter(GLenum filter)
1075{
1076 switch (filter)
1077 {
1078 case GL_NEAREST:
1079 case GL_LINEAR:
1080 {
1081 if (mMagFilter != filter)
1082 {
1083 mMagFilter = filter;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001084 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001085 }
1086 return true;
1087 }
1088 default:
1089 return false;
1090 }
1091}
1092
1093// Returns true on successful wrap state update (valid enum parameter)
1094bool Texture::setWrapS(GLenum wrap)
1095{
1096 switch (wrap)
1097 {
1098 case GL_REPEAT:
1099 case GL_CLAMP_TO_EDGE:
1100 case GL_MIRRORED_REPEAT:
1101 {
1102 if (mWrapS != wrap)
1103 {
1104 mWrapS = wrap;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001105 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001106 }
1107 return true;
1108 }
1109 default:
1110 return false;
1111 }
1112}
1113
1114// Returns true on successful wrap state update (valid enum parameter)
1115bool Texture::setWrapT(GLenum wrap)
1116{
1117 switch (wrap)
1118 {
1119 case GL_REPEAT:
1120 case GL_CLAMP_TO_EDGE:
1121 case GL_MIRRORED_REPEAT:
1122 {
1123 if (mWrapT != wrap)
1124 {
1125 mWrapT = wrap;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001126 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001127 }
1128 return true;
1129 }
1130 default:
1131 return false;
1132 }
1133}
1134
1135GLenum Texture::getMinFilter() const
1136{
1137 return mMinFilter;
1138}
1139
1140GLenum Texture::getMagFilter() const
1141{
1142 return mMagFilter;
1143}
1144
1145GLenum Texture::getWrapS() const
1146{
1147 return mWrapS;
1148}
1149
1150GLenum Texture::getWrapT() const
1151{
1152 return mWrapT;
1153}
1154
daniel@transgaming.com61208202011-03-21 16:38:50 +00001155void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001156{
daniel@transgaming.com73de05a2011-11-09 17:45:24 +00001157 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001158 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001159 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001160 HRESULT result = image->lock(&locked, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001161
1162 if (SUCCEEDED(result))
1163 {
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +00001164 image->loadData(0, 0, image->getWidth(), image->getHeight(), image->getFormat(), image->getType(), unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001165 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001166 }
1167
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001168 image->markDirty();
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001169 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001170 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001171}
1172
daniel@transgaming.com61208202011-03-21 16:38:50 +00001173void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001174{
daniel@transgaming.com73de05a2011-11-09 17:45:24 +00001175 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001176 {
1177 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001178 HRESULT result = image->lock(&locked, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001179
1180 if (SUCCEEDED(result))
1181 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001182 int inputPitch = ComputeCompressedPitch(image->getWidth(), image->getFormat());
1183 int inputSize = ComputeCompressedSize(image->getWidth(), image->getHeight(), image->getFormat());
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +00001184 image->loadCompressedData(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 +00001185 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001186 }
1187
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001188 image->markDirty();
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001189 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001190 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001191}
1192
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001193bool 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 +00001194{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001195 if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001196 {
1197 error(GL_INVALID_VALUE);
1198 return false;
1199 }
1200
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001201 if (IsCompressed(image->getFormat()))
jbauman@chromium.orge2f954c2011-05-03 20:45:27 +00001202 {
1203 error(GL_INVALID_OPERATION);
1204 return false;
1205 }
1206
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001207 if (format != image->getFormat())
jbauman@chromium.orge2f954c2011-05-03 20:45:27 +00001208 {
1209 error(GL_INVALID_OPERATION);
1210 return false;
1211 }
1212
daniel@transgaming.com73de05a2011-11-09 17:45:24 +00001213 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001214 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001215 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001216 HRESULT result = image->lock(&locked, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001217
1218 if (SUCCEEDED(result))
1219 {
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +00001220 image->loadData(xoffset, transformPixelYOffset(yoffset, height, image->getHeight()), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001221 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001222 }
1223
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001224 image->markDirty();
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001225 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001226 }
1227
1228 return true;
1229}
1230
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001231bool 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 +00001232{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001233 if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001234 {
1235 error(GL_INVALID_VALUE);
1236 return false;
1237 }
1238
1239 if (format != getInternalFormat())
1240 {
1241 error(GL_INVALID_OPERATION);
1242 return false;
1243 }
1244
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001245 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001246 {
1247 RECT updateRegion;
1248 updateRegion.left = xoffset;
1249 updateRegion.right = xoffset + width;
1250 updateRegion.bottom = yoffset + height;
1251 updateRegion.top = yoffset;
1252
1253 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001254 HRESULT result = image->lock(&locked, &updateRegion);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001255
1256 if (SUCCEEDED(result))
1257 {
1258 int inputPitch = ComputeCompressedPitch(width, format);
1259 int inputSize = ComputeCompressedSize(width, height, format);
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +00001260 image->loadCompressedData(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 +00001261 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001262 }
1263
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001264 image->markDirty();
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001265 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001266 }
1267
1268 return true;
1269}
1270
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001271// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
1272void 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 +00001273{
1274 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001275 IDirect3DSurface9 *renderTargetData = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001276 D3DSURFACE_DESC description;
1277 renderTarget->GetDesc(&description);
1278
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001279 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001280
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001281 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001282 {
1283 ERR("Could not create matching destination surface.");
1284 return error(GL_OUT_OF_MEMORY);
1285 }
1286
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001287 result = device->GetRenderTargetData(renderTarget, renderTargetData);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001288
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001289 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001290 {
1291 ERR("GetRenderTargetData unexpectedly failed.");
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001292 renderTargetData->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001293 return error(GL_OUT_OF_MEMORY);
1294 }
1295
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001296 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001297 int destYOffset = transformPixelYOffset(yoffset, height, image->getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001298 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001299
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001300 if (image->isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001301 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001302 result = D3DXLoadSurfaceFromSurface(image->getSurface(), NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0);
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001303
1304 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001305 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001306 ERR("Copying surfaces unexpectedly failed.");
1307 renderTargetData->Release();
1308 return error(GL_OUT_OF_MEMORY);
1309 }
1310 }
1311 else
1312 {
1313 D3DLOCKED_RECT sourceLock = {0};
1314 result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001315
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001316 if (FAILED(result))
1317 {
1318 ERR("Failed to lock the source surface (rectangle might be invalid).");
1319 renderTargetData->Release();
1320 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001321 }
1322
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001323 D3DLOCKED_RECT destLock = {0};
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001324 result = image->lock(&destLock, &destRect);
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001325
1326 if (FAILED(result))
1327 {
1328 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1329 renderTargetData->UnlockRect();
1330 renderTargetData->Release();
1331 return error(GL_OUT_OF_MEMORY);
1332 }
1333
1334 if (destLock.pBits && sourceLock.pBits)
1335 {
1336 unsigned char *source = (unsigned char*)sourceLock.pBits;
1337 unsigned char *dest = (unsigned char*)destLock.pBits;
1338
1339 switch (description.Format)
1340 {
1341 case D3DFMT_X8R8G8B8:
1342 case D3DFMT_A8R8G8B8:
1343 switch(image->getD3DFormat())
1344 {
1345 case D3DFMT_L8:
1346 for(int y = 0; y < height; y++)
1347 {
1348 for(int x = 0; x < width; x++)
1349 {
1350 dest[x] = source[x * 4 + 2];
1351 }
1352
1353 source += sourceLock.Pitch;
1354 dest += destLock.Pitch;
1355 }
1356 break;
1357 case D3DFMT_A8L8:
1358 for(int y = 0; y < height; y++)
1359 {
1360 for(int x = 0; x < width; x++)
1361 {
1362 dest[x * 2 + 0] = source[x * 4 + 2];
1363 dest[x * 2 + 1] = source[x * 4 + 3];
1364 }
1365
1366 source += sourceLock.Pitch;
1367 dest += destLock.Pitch;
1368 }
1369 break;
1370 default:
1371 UNREACHABLE();
1372 }
1373 break;
1374 case D3DFMT_R5G6B5:
1375 switch(image->getD3DFormat())
1376 {
1377 case D3DFMT_L8:
1378 for(int y = 0; y < height; y++)
1379 {
1380 for(int x = 0; x < width; x++)
1381 {
1382 unsigned char red = source[x * 2 + 1] & 0xF8;
1383 dest[x] = red | (red >> 5);
1384 }
1385
1386 source += sourceLock.Pitch;
1387 dest += destLock.Pitch;
1388 }
1389 break;
1390 default:
1391 UNREACHABLE();
1392 }
1393 break;
1394 case D3DFMT_A1R5G5B5:
1395 switch(image->getD3DFormat())
1396 {
1397 case D3DFMT_L8:
1398 for(int y = 0; y < height; y++)
1399 {
1400 for(int x = 0; x < width; x++)
1401 {
1402 unsigned char red = source[x * 2 + 1] & 0x7C;
1403 dest[x] = (red << 1) | (red >> 4);
1404 }
1405
1406 source += sourceLock.Pitch;
1407 dest += destLock.Pitch;
1408 }
1409 break;
1410 case D3DFMT_A8L8:
1411 for(int y = 0; y < height; y++)
1412 {
1413 for(int x = 0; x < width; x++)
1414 {
1415 unsigned char red = source[x * 2 + 1] & 0x7C;
1416 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1417 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1418 }
1419
1420 source += sourceLock.Pitch;
1421 dest += destLock.Pitch;
1422 }
1423 break;
1424 default:
1425 UNREACHABLE();
1426 }
1427 break;
1428 default:
1429 UNREACHABLE();
1430 }
1431 }
1432
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001433 image->unlock();
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001434 renderTargetData->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001435 }
1436
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001437 renderTargetData->Release();
1438
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001439 image->markDirty();
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001440 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001441}
1442
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001443IDirect3DBaseTexture9 *Texture::getTexture()
1444{
1445 if (!isComplete())
1446 {
1447 return NULL;
1448 }
1449
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001450 if (!getBaseTexture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001451 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001452 createTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001453 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001454
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +00001455 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001456
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001457 return getBaseTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001458}
1459
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001460bool Texture::hasDirtyParameters() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001461{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001462 return mDirtyParameters;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001463}
1464
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001465bool Texture::hasDirtyImages() const
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001466{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001467 return mDirtyImages;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001468}
1469
1470void Texture::resetDirty()
1471{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001472 mDirtyParameters = false;
1473 mDirtyImages = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001474}
1475
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001476unsigned int Texture::getSerial() const
1477{
1478 return mSerial;
1479}
1480
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001481GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1482{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001483 if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001484 {
1485 return maxlevel;
1486 }
1487 else
1488 {
1489 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1490 return 1;
1491 }
1492}
1493
1494GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1495{
1496 return creationLevels(size, size, maxlevel);
1497}
1498
1499int Texture::levelCount() const
1500{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001501 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001502}
1503
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001504unsigned int Texture::issueSerial()
1505{
1506 return mCurrentSerial++;
1507}
1508
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001509Texture2D::Texture2D(GLuint id) : Texture(id)
1510{
1511 mTexture = NULL;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001512 mSurface = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001513}
1514
1515Texture2D::~Texture2D()
1516{
1517 mColorbufferProxy.set(NULL);
1518
1519 if (mTexture)
1520 {
1521 mTexture->Release();
1522 mTexture = NULL;
1523 }
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001524
1525 if (mSurface)
1526 {
1527 mSurface->setBoundTexture(NULL);
1528 mSurface = NULL;
1529 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001530}
1531
1532GLenum Texture2D::getTarget() const
1533{
1534 return GL_TEXTURE_2D;
1535}
1536
daniel@transgaming.com61208202011-03-21 16:38:50 +00001537GLsizei Texture2D::getWidth() const
1538{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001539 return mImageArray[0].getWidth();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001540}
1541
1542GLsizei Texture2D::getHeight() const
1543{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001544 return mImageArray[0].getHeight();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001545}
1546
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001547GLenum Texture2D::getInternalFormat() const
1548{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001549 return mImageArray[0].getFormat();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001550}
1551
daniel@transgaming.com61208202011-03-21 16:38:50 +00001552GLenum Texture2D::getType() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001553{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001554 return mImageArray[0].getType();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001555}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001556
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001557D3DFORMAT Texture2D::getD3DFormat() const
1558{
1559 return mImageArray[0].getD3DFormat();
1560}
1561
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001562void Texture2D::redefineImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type, bool forceRedefine)
daniel@transgaming.com61208202011-03-21 16:38:50 +00001563{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001564 GLsizei textureWidth = mImageArray[0].getWidth();
1565 GLsizei textureHeight = mImageArray[0].getHeight();
1566 GLenum textureFormat = mImageArray[0].getFormat();
1567 GLenum textureType = mImageArray[0].getType();
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001568
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001569 mImageArray[level].redefine(format, width, height, type);
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00001570
daniel@transgaming.com61208202011-03-21 16:38:50 +00001571 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001572 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001573 return;
1574 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001575
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001576 bool widthOkay = (textureWidth >> level == width) || (textureWidth >> level == 0 && width == 1);
1577 bool heightOkay = (textureHeight >> level == height) || (textureHeight >> level == 0 && height == 1);
1578 bool textureOkay = (widthOkay && heightOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00001579
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00001580 if (!textureOkay || forceRedefine || mSurface)
daniel@transgaming.com61208202011-03-21 16:38:50 +00001581 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001582 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1583 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001584 mImageArray[i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001585 }
1586
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001587 mTexture->Release();
1588 mTexture = NULL;
1589 mDirtyImages = true;
1590 mIsRenderable = false;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001591
1592 if (mSurface)
1593 {
1594 mSurface->setBoundTexture(NULL);
1595 mSurface = NULL;
1596 }
apatrick@chromium.org57a2cd62011-06-08 00:04:07 +00001597
1598 mColorbufferProxy.set(NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001599 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001600}
1601
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001602void 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 +00001603{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001604 redefineImage(level, format, width, height, type, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001605
daniel@transgaming.com61208202011-03-21 16:38:50 +00001606 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001607}
1608
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001609void Texture2D::bindTexImage(egl::Surface *surface)
1610{
1611 GLenum format;
1612
1613 switch(surface->getFormat())
1614 {
1615 case D3DFMT_A8R8G8B8:
1616 format = GL_RGBA;
1617 break;
1618 case D3DFMT_X8R8G8B8:
1619 format = GL_RGB;
1620 break;
1621 default:
1622 UNIMPLEMENTED();
1623 return;
1624 }
1625
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001626 redefineImage(0, format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE, true);
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001627
1628 IDirect3DTexture9 *texture = surface->getOffscreenTexture();
1629
1630 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001631 mDirtyImages = true;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001632 mIsRenderable = true;
1633 mSurface = surface;
1634 mSurface->setBoundTexture(this);
1635}
1636
1637void Texture2D::releaseTexImage()
1638{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001639 redefineImage(0, GL_RGB, 0, 0, GL_UNSIGNED_BYTE, true);
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001640}
1641
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001642void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001643{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001644 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001645
daniel@transgaming.com61208202011-03-21 16:38:50 +00001646 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001647}
1648
1649void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1650{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001651 ASSERT(mImageArray[level].getSurface() != NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001652
1653 if (level < levelCount())
1654 {
1655 IDirect3DSurface9 *destLevel = NULL;
1656 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1657
1658 ASSERT(SUCCEEDED(result));
1659
1660 if (SUCCEEDED(result))
1661 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001662 Image *image = &mImageArray[level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001663
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001664 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->getHeight());;
daniel@transgaming.comb612f882011-11-09 17:44:31 +00001665 POINT destPoint = {sourceRect.left, sourceRect.top};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001666
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001667 result = getDevice()->UpdateSurface(image->getSurface(), &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001668 ASSERT(SUCCEEDED(result));
1669
1670 destLevel->Release();
1671
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001672 image->markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001673 }
1674 }
1675}
1676
1677void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1678{
1679 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1680 {
1681 commitRect(level, xoffset, yoffset, width, height);
1682 }
1683}
1684
1685void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1686{
1687 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1688 {
1689 commitRect(level, xoffset, yoffset, width, height);
1690 }
1691}
1692
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001693void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001694{
1695 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1696
1697 if (!renderTarget)
1698 {
1699 ERR("Failed to retrieve the render target.");
1700 return error(GL_OUT_OF_MEMORY);
1701 }
1702
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001703 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001704
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001705 if (!mImageArray[level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001706 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001707 copyToImage(&mImageArray[level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001708 }
1709 else
1710 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001711 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001712 {
1713 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001714 }
daniel@transgaming.com3b3c1d42011-06-08 20:38:09 +00001715
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001716 mImageArray[level].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001717
1718 if (width != 0 && height != 0 && level < levelCount())
1719 {
1720 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1721 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1722 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1723 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1724 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001725
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001726 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[level].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001727
1728 IDirect3DSurface9 *dest;
1729 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1730
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001731 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001732 dest->Release();
1733 }
1734 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001735}
1736
1737void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1738{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001739 if (xoffset + width > mImageArray[level].getWidth() || yoffset + height > mImageArray[level].getHeight())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001740 {
1741 return error(GL_INVALID_VALUE);
1742 }
1743
1744 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1745
1746 if (!renderTarget)
1747 {
1748 ERR("Failed to retrieve the render target.");
1749 return error(GL_OUT_OF_MEMORY);
1750 }
1751
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001752 if (!mImageArray[level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001753 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001754 copyToImage(&mImageArray[level], xoffset, yoffset, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001755 }
1756 else
1757 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001758 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001759 {
1760 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001761 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001762
1763 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001764
1765 if (level < levelCount())
1766 {
1767 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1768 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1769 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1770 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1771 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1772
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001773 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001774
1775 IDirect3DSurface9 *dest;
1776 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1777
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001778 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0].getFormat(), xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001779 dest->Release();
1780 }
1781 }
1782}
1783
1784// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1785bool Texture2D::isComplete() const
1786{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001787 GLsizei width = mImageArray[0].getWidth();
1788 GLsizei height = mImageArray[0].getHeight();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001789
1790 if (width <= 0 || height <= 0)
1791 {
1792 return false;
1793 }
1794
1795 bool mipmapping = false;
1796
1797 switch (mMinFilter)
1798 {
1799 case GL_NEAREST:
1800 case GL_LINEAR:
1801 mipmapping = false;
1802 break;
1803 case GL_NEAREST_MIPMAP_NEAREST:
1804 case GL_LINEAR_MIPMAP_NEAREST:
1805 case GL_NEAREST_MIPMAP_LINEAR:
1806 case GL_LINEAR_MIPMAP_LINEAR:
1807 mipmapping = true;
1808 break;
1809 default: UNREACHABLE();
1810 }
1811
1812 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1813 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1814 {
1815 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1816 {
1817 return false;
1818 }
1819 }
1820
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001821 bool npot = getContext()->supportsNonPower2Texture();
1822
1823 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001824 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001825 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
1826 (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1827 {
1828 return false;
1829 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001830 }
1831
1832 if (mipmapping)
1833 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001834 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001835 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001836 if (!isPow2(width) || !isPow2(height))
1837 {
1838 return false;
1839 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001840 }
1841
1842 int q = log2(std::max(width, height));
1843
1844 for (int level = 1; level <= q; level++)
1845 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001846 if (mImageArray[level].getFormat() != mImageArray[0].getFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001847 {
1848 return false;
1849 }
1850
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001851 if (mImageArray[level].getType() != mImageArray[0].getType())
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001852 {
1853 return false;
1854 }
1855
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001856 if (mImageArray[level].getWidth() != std::max(1, width >> level))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001857 {
1858 return false;
1859 }
1860
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001861 if (mImageArray[level].getHeight() != std::max(1, height >> level))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001862 {
1863 return false;
1864 }
1865 }
1866 }
1867
1868 return true;
1869}
1870
1871bool Texture2D::isCompressed() const
1872{
1873 return IsCompressed(getInternalFormat());
1874}
1875
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001876IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1877{
1878 return mTexture;
1879}
1880
1881// Constructs a Direct3D 9 texture resource from the texture images
1882void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001883{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001884 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001885 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001886 GLint levels = creationLevels(mImageArray[0].getWidth(), mImageArray[0].getHeight(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001887
daniel@transgaming.com61208202011-03-21 16:38:50 +00001888 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001889 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 +00001890
1891 if (FAILED(result))
1892 {
1893 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001894 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001895 }
1896
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001897 if (mTexture)
1898 {
1899 mTexture->Release();
1900 }
1901
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001902 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001903 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001904 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001905}
1906
1907void Texture2D::updateTexture()
1908{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001909 int levels = levelCount();
1910
1911 for (int level = 0; level < levels; level++)
1912 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00001913 Image *image = &mImageArray[level];
1914
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001915 if (image->isDirty())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001916 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001917 commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001918 }
1919 }
1920}
1921
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001922void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001923{
1924 IDirect3DTexture9 *texture = NULL;
1925
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001926 if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001927 {
1928 egl::Display *display = getDisplay();
1929 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001930 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001931 GLint levels = creationLevels(mImageArray[0].getWidth(), mImageArray[0].getHeight(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001932
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001933 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 +00001934
1935 if (FAILED(result))
1936 {
1937 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001938 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001939 }
1940
1941 if (mTexture != NULL)
1942 {
1943 int levels = levelCount();
1944 for (int i = 0; i < levels; i++)
1945 {
1946 IDirect3DSurface9 *source;
1947 result = mTexture->GetSurfaceLevel(i, &source);
1948
1949 if (FAILED(result))
1950 {
1951 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1952
1953 texture->Release();
1954
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001955 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001956 }
1957
1958 IDirect3DSurface9 *dest;
1959 result = texture->GetSurfaceLevel(i, &dest);
1960
1961 if (FAILED(result))
1962 {
1963 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1964
1965 texture->Release();
1966 source->Release();
1967
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001968 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001969 }
1970
1971 display->endScene();
1972 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1973
1974 if (FAILED(result))
1975 {
1976 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1977
1978 texture->Release();
1979 source->Release();
1980 dest->Release();
1981
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001982 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001983 }
1984
1985 source->Release();
1986 dest->Release();
1987 }
1988 }
1989 }
1990
1991 if (mTexture != NULL)
1992 {
1993 mTexture->Release();
1994 }
1995
1996 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001997 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001998 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001999}
2000
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002001void Texture2D::generateMipmaps()
2002{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002003 if (!getContext()->supportsNonPower2Texture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002004 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002005 if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight()))
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002006 {
2007 return error(GL_INVALID_OPERATION);
2008 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002009 }
2010
2011 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002012 unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight()));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002013 for (unsigned int i = 1; i <= q; i++)
2014 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002015 mImageArray[i].redefine(mImageArray[0].getFormat(),
2016 std::max(mImageArray[0].getWidth() >> i, 1),
2017 std::max(mImageArray[0].getHeight() >> i, 1),
2018 mImageArray[0].getType());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002019 }
2020
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002021 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002022 {
2023 if (mTexture == NULL)
2024 {
2025 ERR(" failed because mTexture was null.");
2026 return;
2027 }
2028
2029 for (unsigned int i = 1; i <= q; i++)
2030 {
2031 IDirect3DSurface9 *upper = NULL;
2032 IDirect3DSurface9 *lower = NULL;
2033
2034 mTexture->GetSurfaceLevel(i-1, &upper);
2035 mTexture->GetSurfaceLevel(i, &lower);
2036
2037 if (upper != NULL && lower != NULL)
2038 {
2039 getBlitter()->boxFilter(upper, lower);
2040 }
2041
2042 if (upper != NULL) upper->Release();
2043 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002044
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002045 mImageArray[i].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002046 }
2047 }
2048 else
2049 {
2050 for (unsigned int i = 1; i <= q; i++)
2051 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002052 if (mImageArray[i].getSurface() == NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002053 {
2054 return error(GL_OUT_OF_MEMORY);
2055 }
2056
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002057 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 +00002058 {
2059 ERR(" failed to load filter %d to %d.", i - 1, i);
2060 }
2061
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002062 mImageArray[i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002063 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002064 }
2065}
2066
2067Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
2068{
2069 if (target != GL_TEXTURE_2D)
2070 {
2071 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2072 }
2073
2074 if (mColorbufferProxy.get() == NULL)
2075 {
2076 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2077 }
2078
2079 return mColorbufferProxy.get();
2080}
2081
2082IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
2083{
2084 ASSERT(target == GL_TEXTURE_2D);
2085
daniel@transgaming.com61208202011-03-21 16:38:50 +00002086 if (!mIsRenderable)
2087 {
2088 convertToRenderTarget();
2089 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002090
2091 if (mTexture == NULL)
2092 {
2093 return NULL;
2094 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002095
2096 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002097
2098 IDirect3DSurface9 *renderTarget = NULL;
2099 mTexture->GetSurfaceLevel(0, &renderTarget);
2100
2101 return renderTarget;
2102}
2103
2104TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
2105{
2106 mTexture = NULL;
2107}
2108
2109TextureCubeMap::~TextureCubeMap()
2110{
2111 for (int i = 0; i < 6; i++)
2112 {
2113 mFaceProxies[i].set(NULL);
2114 }
2115
2116 if (mTexture)
2117 {
2118 mTexture->Release();
2119 mTexture = NULL;
2120 }
2121}
2122
2123GLenum TextureCubeMap::getTarget() const
2124{
2125 return GL_TEXTURE_CUBE_MAP;
2126}
2127
daniel@transgaming.com61208202011-03-21 16:38:50 +00002128GLsizei TextureCubeMap::getWidth() const
2129{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002130 return mImageArray[0][0].getWidth();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002131}
2132
2133GLsizei TextureCubeMap::getHeight() const
2134{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002135 return mImageArray[0][0].getHeight();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002136}
2137
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002138GLenum TextureCubeMap::getInternalFormat() const
2139{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002140 return mImageArray[0][0].getFormat();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002141}
2142
daniel@transgaming.com61208202011-03-21 16:38:50 +00002143GLenum TextureCubeMap::getType() const
2144{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002145 return mImageArray[0][0].getType();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002146}
2147
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002148D3DFORMAT TextureCubeMap::getD3DFormat() const
2149{
2150 return mImageArray[0][0].getD3DFormat();
2151}
2152
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002153void 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 +00002154{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002155 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002156}
2157
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002158void 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 +00002159{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002160 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002161}
2162
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002163void 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 +00002164{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002165 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002166}
2167
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002168void 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 +00002169{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002170 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002171}
2172
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002173void 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 +00002174{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002175 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002176}
2177
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002178void 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 +00002179{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002180 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002181}
2182
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002183void 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 +00002184{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002185 redefineImage(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002186
daniel@transgaming.com61208202011-03-21 16:38:50 +00002187 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002188}
2189
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002190void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002191{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002192 ASSERT(mImageArray[face][level].getSurface() != NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002193
2194 if (level < levelCount())
2195 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002196 IDirect3DSurface9 *destLevel = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002197 ASSERT(destLevel != NULL);
2198
2199 if (destLevel != NULL)
2200 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002201 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002202
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002203 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->getHeight());;
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002204 POINT destPoint = {sourceRect.left, sourceRect.top};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002205
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002206 HRESULT result = getDevice()->UpdateSurface(image->getSurface(), &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002207 ASSERT(SUCCEEDED(result));
2208
2209 destLevel->Release();
2210
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002211 image->markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002212 }
2213 }
2214}
2215
2216void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2217{
2218 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
2219 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002220 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002221 }
2222}
2223
2224void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
2225{
2226 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
2227 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002228 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002229 }
2230}
2231
2232// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
2233bool TextureCubeMap::isComplete() const
2234{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002235 int size = mImageArray[0][0].getWidth();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002236
2237 if (size <= 0)
2238 {
2239 return false;
2240 }
2241
2242 bool mipmapping;
2243
2244 switch (mMinFilter)
2245 {
2246 case GL_NEAREST:
2247 case GL_LINEAR:
2248 mipmapping = false;
2249 break;
2250 case GL_NEAREST_MIPMAP_NEAREST:
2251 case GL_LINEAR_MIPMAP_NEAREST:
2252 case GL_NEAREST_MIPMAP_LINEAR:
2253 case GL_LINEAR_MIPMAP_LINEAR:
2254 mipmapping = true;
2255 break;
2256 default: UNREACHABLE();
2257 }
2258
2259 for (int face = 0; face < 6; face++)
2260 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002261 if (mImageArray[face][0].getWidth() != size || mImageArray[face][0].getHeight() != size)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002262 {
2263 return false;
2264 }
2265 }
2266
2267 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
2268 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
2269 {
2270 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
2271 {
2272 return false;
2273 }
2274 }
2275
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002276 bool npot = getContext()->supportsNonPower2Texture();
2277
2278 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002279 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002280 if ((getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE) && !isPow2(size))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002281 {
2282 return false;
2283 }
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002284 }
2285
2286 if (mipmapping)
2287 {
2288 if (!npot)
2289 {
2290 if (!isPow2(size))
2291 {
2292 return false;
2293 }
2294 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002295
2296 int q = log2(size);
2297
2298 for (int face = 0; face < 6; face++)
2299 {
2300 for (int level = 1; level <= q; level++)
2301 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002302 if (mImageArray[face][level].getFormat() != mImageArray[0][0].getFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002303 {
2304 return false;
2305 }
2306
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002307 if (mImageArray[face][level].getType() != mImageArray[0][0].getType())
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002308 {
2309 return false;
2310 }
2311
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002312 if (mImageArray[face][level].getWidth() != std::max(1, size >> level))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002313 {
2314 return false;
2315 }
2316
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002317 ASSERT(mImageArray[face][level].getHeight() == mImageArray[face][level].getWidth());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002318 }
2319 }
2320 }
2321
2322 return true;
2323}
2324
2325bool TextureCubeMap::isCompressed() const
2326{
2327 return IsCompressed(getInternalFormat());
2328}
2329
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002330IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
2331{
2332 return mTexture;
2333}
2334
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002335// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002336void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002337{
2338 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002339 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002340 GLint levels = creationLevels(mImageArray[0][0].getWidth(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002341
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002342 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002343 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].getWidth(), levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002344
2345 if (FAILED(result))
2346 {
2347 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002348 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002349 }
2350
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002351 if (mTexture)
2352 {
2353 mTexture->Release();
2354 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002355
2356 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002357 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002358 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002359}
2360
2361void TextureCubeMap::updateTexture()
2362{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002363 for (int face = 0; face < 6; face++)
2364 {
2365 int levels = levelCount();
2366 for (int level = 0; level < levels; level++)
2367 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002368 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002369
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00002370 if (image->isDirty())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002371 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002372 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002373 }
2374 }
2375 }
2376}
2377
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002378void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002379{
2380 IDirect3DCubeTexture9 *texture = NULL;
2381
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002382 if (mImageArray[0][0].getWidth() != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002383 {
2384 egl::Display *display = getDisplay();
2385 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002386 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002387 GLint levels = creationLevels(mImageArray[0][0].getWidth(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002388
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002389 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].getWidth(), levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002390
2391 if (FAILED(result))
2392 {
2393 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002394 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002395 }
2396
2397 if (mTexture != NULL)
2398 {
2399 int levels = levelCount();
2400 for (int f = 0; f < 6; f++)
2401 {
2402 for (int i = 0; i < levels; i++)
2403 {
2404 IDirect3DSurface9 *source;
2405 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2406
2407 if (FAILED(result))
2408 {
2409 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2410
2411 texture->Release();
2412
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002413 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002414 }
2415
2416 IDirect3DSurface9 *dest;
2417 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2418
2419 if (FAILED(result))
2420 {
2421 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2422
2423 texture->Release();
2424 source->Release();
2425
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002426 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002427 }
2428
2429 display->endScene();
2430 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2431
2432 if (FAILED(result))
2433 {
2434 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2435
2436 texture->Release();
2437 source->Release();
2438 dest->Release();
2439
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002440 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002441 }
daniel@transgaming.coma1a86202011-08-09 13:41:08 +00002442
2443 source->Release();
2444 dest->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002445 }
2446 }
2447 }
2448 }
2449
2450 if (mTexture != NULL)
2451 {
2452 mTexture->Release();
2453 }
2454
2455 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002456 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002457 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002458}
2459
daniel@transgaming.com61208202011-03-21 16:38:50 +00002460void 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 +00002461{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002462 redefineImage(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002463
daniel@transgaming.com61208202011-03-21 16:38:50 +00002464 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002465}
2466
2467unsigned int TextureCubeMap::faceIndex(GLenum face)
2468{
2469 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2470 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2471 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2472 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2473 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2474
2475 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2476}
2477
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002478void TextureCubeMap::redefineImage(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002479{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002480 GLsizei textureWidth = mImageArray[0][0].getWidth();
2481 GLsizei textureHeight = mImageArray[0][0].getHeight();
2482 GLenum textureFormat = mImageArray[0][0].getFormat();
2483 GLenum textureType = mImageArray[0][0].getType();
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002484
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002485 mImageArray[face][level].redefine(format, width, height, type);
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00002486
daniel@transgaming.com61208202011-03-21 16:38:50 +00002487 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002488 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002489 return;
2490 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002491
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002492 bool sizeOkay = (textureWidth >> level == width);
2493 bool textureOkay = (sizeOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002494
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00002495 if (!textureOkay)
daniel@transgaming.com61208202011-03-21 16:38:50 +00002496 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002497 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2498 {
2499 for (int f = 0; f < 6; f++)
2500 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002501 mImageArray[f][i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002502 }
2503 }
2504
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002505 mTexture->Release();
2506 mTexture = NULL;
2507 mDirtyImages = true;
2508 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002509 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002510}
2511
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002512void 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 +00002513{
2514 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2515
2516 if (!renderTarget)
2517 {
2518 ERR("Failed to retrieve the render target.");
2519 return error(GL_OUT_OF_MEMORY);
2520 }
2521
2522 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002523 redefineImage(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002524
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002525 if (!mImageArray[faceindex][level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002526 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002527 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002528 }
2529 else
2530 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002531 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002532 {
2533 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002534 }
daniel@transgaming.com3b3c1d42011-06-08 20:38:09 +00002535
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002536 mImageArray[faceindex][level].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002537
2538 ASSERT(width == height);
2539
2540 if (width > 0 && level < levelCount())
2541 {
2542 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2543 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2544 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2545 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2546 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2547
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002548 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[faceindex][level].getWidth());
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002549
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002550 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2551
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002552 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002553 dest->Release();
2554 }
2555 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002556}
2557
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002558IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum target, unsigned int level)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002559{
2560 if (mTexture == NULL)
2561 {
2562 UNREACHABLE();
2563 return NULL;
2564 }
2565
2566 IDirect3DSurface9 *surface = NULL;
2567
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002568 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), level, &surface);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002569
2570 return (SUCCEEDED(hr)) ? surface : NULL;
2571}
2572
2573void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2574{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002575 GLsizei size = mImageArray[faceIndex(target)][level].getWidth();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002576
2577 if (xoffset + width > size || yoffset + height > size)
2578 {
2579 return error(GL_INVALID_VALUE);
2580 }
2581
2582 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2583
2584 if (!renderTarget)
2585 {
2586 ERR("Failed to retrieve the render target.");
2587 return error(GL_OUT_OF_MEMORY);
2588 }
2589
2590 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com01dae852011-11-09 17:44:53 +00002591
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002592 if (!mImageArray[faceindex][level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002593 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002594 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002595 }
2596 else
2597 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002598 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002599 {
2600 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002601 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002602
2603 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002604
2605 if (level < levelCount())
2606 {
2607 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2608 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2609 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2610 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2611 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2612
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002613 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].getWidth());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002614
2615 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2616
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002617 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0][0].getFormat(), xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002618 dest->Release();
2619 }
2620 }
2621}
2622
2623bool TextureCubeMap::isCubeComplete() const
2624{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002625 if (mImageArray[0][0].getWidth() == 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002626 {
2627 return false;
2628 }
2629
2630 for (unsigned int f = 1; f < 6; f++)
2631 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002632 if (mImageArray[f][0].getWidth() != mImageArray[0][0].getWidth()
2633 || mImageArray[f][0].getFormat() != mImageArray[0][0].getFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002634 {
2635 return false;
2636 }
2637 }
2638
2639 return true;
2640}
2641
2642void TextureCubeMap::generateMipmaps()
2643{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002644 if (!isCubeComplete())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002645 {
2646 return error(GL_INVALID_OPERATION);
2647 }
2648
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002649 if (!getContext()->supportsNonPower2Texture())
2650 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002651 if (!isPow2(mImageArray[0][0].getWidth()))
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002652 {
2653 return error(GL_INVALID_OPERATION);
2654 }
2655 }
2656
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002657 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002658 unsigned int q = log2(mImageArray[0][0].getWidth());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002659 for (unsigned int f = 0; f < 6; f++)
2660 {
2661 for (unsigned int i = 1; i <= q; i++)
2662 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002663 mImageArray[f][i].redefine(mImageArray[f][0].getFormat(),
2664 std::max(mImageArray[f][0].getWidth() >> i, 1),
2665 std::max(mImageArray[f][0].getWidth() >> i, 1),
2666 mImageArray[f][0].getType());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002667 }
2668 }
2669
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002670 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002671 {
2672 if (mTexture == NULL)
2673 {
2674 return;
2675 }
2676
2677 for (unsigned int f = 0; f < 6; f++)
2678 {
2679 for (unsigned int i = 1; i <= q; i++)
2680 {
2681 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2682 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2683
2684 if (upper != NULL && lower != NULL)
2685 {
2686 getBlitter()->boxFilter(upper, lower);
2687 }
2688
2689 if (upper != NULL) upper->Release();
2690 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002691
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002692 mImageArray[f][i].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002693 }
2694 }
2695 }
2696 else
2697 {
2698 for (unsigned int f = 0; f < 6; f++)
2699 {
2700 for (unsigned int i = 1; i <= q; i++)
2701 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002702 if (mImageArray[f][i].getSurface() == NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002703 {
2704 return error(GL_OUT_OF_MEMORY);
2705 }
2706
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002707 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 +00002708 {
2709 ERR(" failed to load filter %d to %d.", i - 1, i);
2710 }
2711
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002712 mImageArray[f][i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002713 }
2714 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002715 }
2716}
2717
2718Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2719{
2720 if (!IsCubemapTextureTarget(target))
2721 {
2722 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2723 }
2724
2725 unsigned int face = faceIndex(target);
2726
2727 if (mFaceProxies[face].get() == NULL)
2728 {
2729 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2730 }
2731
2732 return mFaceProxies[face].get();
2733}
2734
2735IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2736{
2737 ASSERT(IsCubemapTextureTarget(target));
2738
daniel@transgaming.com61208202011-03-21 16:38:50 +00002739 if (!mIsRenderable)
2740 {
2741 convertToRenderTarget();
2742 }
2743
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002744 if (mTexture == NULL)
2745 {
2746 return NULL;
2747 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002748
2749 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002750
2751 IDirect3DSurface9 *renderTarget = NULL;
2752 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2753
2754 return renderTarget;
2755}
2756
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002757}