blob: affe6b87229cefca222462d5c7f00d5c436b727e [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.com41634052011-11-09 17:46:24 +000045bool Image::redefine(GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000046{
daniel@transgaming.com4c0a7712011-11-09 17:45:19 +000047 if (mWidth != width ||
48 mHeight != height ||
49 mFormat != format ||
50 mType != type)
51 {
daniel@transgaming.com41634052011-11-09 17:46:24 +000052 mWidth = width;
53 mHeight = height;
54 mFormat = format;
55 mType = type;
56
daniel@transgaming.com4c0a7712011-11-09 17:45:19 +000057 if (mSurface)
58 {
59 mSurface->Release();
60 mSurface = NULL;
61 }
daniel@transgaming.com41634052011-11-09 17:46:24 +000062
63 return true;
daniel@transgaming.com4c0a7712011-11-09 17:45:19 +000064 }
65
daniel@transgaming.com41634052011-11-09 17:46:24 +000066 return false;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000067}
68
69void Image::createSurface()
70{
71 if(mSurface)
72 {
73 return;
74 }
75
76 IDirect3DTexture9 *newTexture = NULL;
77 IDirect3DSurface9 *newSurface = NULL;
78
79 if (mWidth != 0 && mHeight != 0)
80 {
81 int levelToFetch = 0;
82 GLsizei requestWidth = mWidth;
83 GLsizei requestHeight = mHeight;
84 if (IsCompressed(mFormat) && (mWidth % 4 != 0 || mHeight % 4 != 0))
85 {
86 bool isMult4 = false;
87 int upsampleCount = 0;
88 while (!isMult4)
89 {
90 requestWidth <<= 1;
91 requestHeight <<= 1;
92 upsampleCount++;
93 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
94 {
95 isMult4 = true;
96 }
97 }
98 levelToFetch = upsampleCount;
99 }
100
101 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, getD3DFormat(),
102 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
103
104 if (FAILED(result))
105 {
106 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com73de05a2011-11-09 17:45:24 +0000107 ERR("Creating image surface failed.");
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000108 return error(GL_OUT_OF_MEMORY);
109 }
110
111 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
112 newTexture->Release();
113 }
114
115 mSurface = newSurface;
daniel@transgaming.com839fb9b2011-11-09 17:45:43 +0000116 mDirty = false;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000117}
118
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +0000119HRESULT Image::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect)
120{
121 createSurface();
122
123 HRESULT result = D3DERR_INVALIDCALL;
124
125 if (mSurface)
126 {
127 result = mSurface->LockRect(lockedRect, rect, 0);
128 ASSERT(SUCCEEDED(result));
129
130 mDirty = true;
131 }
132
133 return result;
134}
135
136void Image::unlock()
137{
138 if (mSurface)
139 {
140 HRESULT result = mSurface->UnlockRect();
141 ASSERT(SUCCEEDED(result));
142 }
143}
144
daniel@transgaming.comde631782011-11-09 17:45:04 +0000145bool Image::isRenderable() const
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000146{
147 switch(getD3DFormat())
148 {
149 case D3DFMT_L8:
150 case D3DFMT_A8L8:
151 case D3DFMT_DXT1:
gman@chromium.org50c526d2011-08-10 05:19:44 +0000152 case D3DFMT_DXT3:
153 case D3DFMT_DXT5:
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000154 return false;
155 case D3DFMT_A8R8G8B8:
156 case D3DFMT_X8R8G8B8:
157 case D3DFMT_A16B16G16R16F:
158 case D3DFMT_A32B32G32R32F:
159 return true;
160 default:
161 UNREACHABLE();
162 }
163
164 return false;
165}
166
daniel@transgaming.comde631782011-11-09 17:45:04 +0000167D3DFORMAT Image::getD3DFormat() const
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000168{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000169 if (mFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
170 mFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000171 {
172 return D3DFMT_DXT1;
173 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000174 else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE)
gman@chromium.org50c526d2011-08-10 05:19:44 +0000175 {
176 return D3DFMT_DXT3;
177 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000178 else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE)
gman@chromium.org50c526d2011-08-10 05:19:44 +0000179 {
180 return D3DFMT_DXT5;
181 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000182 else if (mType == GL_FLOAT)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000183 {
184 return D3DFMT_A32B32G32R32F;
185 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000186 else if (mType == GL_HALF_FLOAT_OES)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000187 {
188 return D3DFMT_A16B16G16R16F;
189 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000190 else if (mType == GL_UNSIGNED_BYTE)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000191 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000192 if (mFormat == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000193 {
194 return D3DFMT_L8;
195 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000196 else if (mFormat == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000197 {
198 return D3DFMT_A8L8;
199 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000200 else if (mFormat == GL_RGB)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000201 {
202 return D3DFMT_X8R8G8B8;
203 }
204
205 return D3DFMT_A8R8G8B8;
206 }
207
208 return D3DFMT_A8R8G8B8;
209}
210
daniel@transgaming.com73de05a2011-11-09 17:45:24 +0000211IDirect3DSurface9 *Image::getSurface()
212{
213 createSurface();
214
215 return mSurface;
216}
217
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000218// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
219// into the target pixel rectangle at output with outputPitch bytes in between each line.
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000220void Image::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum type,
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000221 GLint unpackAlignment, const void *input, size_t outputPitch, void *output) const
222{
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000223 GLsizei inputPitch = -ComputePitch(width, mFormat, type, unpackAlignment);
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000224 input = ((char*)input) - inputPitch * (height - 1);
225
226 switch (type)
227 {
228 case GL_UNSIGNED_BYTE:
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000229 switch (mFormat)
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000230 {
231 case GL_ALPHA:
232 loadAlphaData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
233 break;
234 case GL_LUMINANCE:
235 loadLuminanceData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, getD3DFormat() == D3DFMT_L8);
236 break;
237 case GL_LUMINANCE_ALPHA:
238 loadLuminanceAlphaData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, getD3DFormat() == D3DFMT_A8L8);
239 break;
240 case GL_RGB:
241 loadRGBUByteData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
242 break;
243 case GL_RGBA:
244 if (supportsSSE2())
245 {
246 loadRGBAUByteDataSSE2(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
247 }
248 else
249 {
250 loadRGBAUByteData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
251 }
252 break;
253 case GL_BGRA_EXT:
254 loadBGRAData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
255 break;
256 default: UNREACHABLE();
257 }
258 break;
259 case GL_UNSIGNED_SHORT_5_6_5:
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000260 switch (mFormat)
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000261 {
262 case GL_RGB:
263 loadRGB565Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
264 break;
265 default: UNREACHABLE();
266 }
267 break;
268 case GL_UNSIGNED_SHORT_4_4_4_4:
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000269 switch (mFormat)
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000270 {
271 case GL_RGBA:
272 loadRGBA4444Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
273 break;
274 default: UNREACHABLE();
275 }
276 break;
277 case GL_UNSIGNED_SHORT_5_5_5_1:
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000278 switch (mFormat)
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000279 {
280 case GL_RGBA:
281 loadRGBA5551Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
282 break;
283 default: UNREACHABLE();
284 }
285 break;
286 case GL_FLOAT:
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000287 switch (mFormat)
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000288 {
289 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
290 case GL_ALPHA:
291 loadAlphaFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
292 break;
293 case GL_LUMINANCE:
294 loadLuminanceFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
295 break;
296 case GL_LUMINANCE_ALPHA:
297 loadLuminanceAlphaFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
298 break;
299 case GL_RGB:
300 loadRGBFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
301 break;
302 case GL_RGBA:
303 loadRGBAFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
304 break;
305 default: UNREACHABLE();
306 }
307 break;
308 case GL_HALF_FLOAT_OES:
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000309 switch (mFormat)
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000310 {
311 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
312 case GL_ALPHA:
313 loadAlphaHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
314 break;
315 case GL_LUMINANCE:
316 loadLuminanceHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
317 break;
318 case GL_LUMINANCE_ALPHA:
319 loadLuminanceAlphaHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
320 break;
321 case GL_RGB:
322 loadRGBHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
323 break;
324 case GL_RGBA:
325 loadRGBAHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
326 break;
327 default: UNREACHABLE();
328 }
329 break;
330 default: UNREACHABLE();
331 }
332}
333
334void Image::loadAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
335 int inputPitch, const void *input, size_t outputPitch, void *output) const
336{
337 const unsigned char *source = NULL;
338 unsigned char *dest = NULL;
339
340 for (int y = 0; y < height; y++)
341 {
342 source = static_cast<const unsigned char*>(input) + y * inputPitch;
343 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
344 for (int x = 0; x < width; x++)
345 {
346 dest[4 * x + 0] = 0;
347 dest[4 * x + 1] = 0;
348 dest[4 * x + 2] = 0;
349 dest[4 * x + 3] = source[x];
350 }
351 }
352}
353
354void Image::loadAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
355 int inputPitch, const void *input, size_t outputPitch, void *output) const
356{
357 const float *source = NULL;
358 float *dest = NULL;
359
360 for (int y = 0; y < height; y++)
361 {
362 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
363 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
364 for (int x = 0; x < width; x++)
365 {
366 dest[4 * x + 0] = 0;
367 dest[4 * x + 1] = 0;
368 dest[4 * x + 2] = 0;
369 dest[4 * x + 3] = source[x];
370 }
371 }
372}
373
374void Image::loadAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
375 int inputPitch, const void *input, size_t outputPitch, void *output) const
376{
377 const unsigned short *source = NULL;
378 unsigned short *dest = NULL;
379
380 for (int y = 0; y < height; y++)
381 {
382 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
383 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
384 for (int x = 0; x < width; x++)
385 {
386 dest[4 * x + 0] = 0;
387 dest[4 * x + 1] = 0;
388 dest[4 * x + 2] = 0;
389 dest[4 * x + 3] = source[x];
390 }
391 }
392}
393
394void Image::loadLuminanceData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
395 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
396{
397 const int destBytesPerPixel = native? 1: 4;
398 const unsigned char *source = NULL;
399 unsigned char *dest = NULL;
400
401 for (int y = 0; y < height; y++)
402 {
403 source = static_cast<const unsigned char*>(input) + y * inputPitch;
404 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
405
406 if (!native) // BGRA8 destination format
407 {
408 for (int x = 0; x < width; x++)
409 {
410 dest[4 * x + 0] = source[x];
411 dest[4 * x + 1] = source[x];
412 dest[4 * x + 2] = source[x];
413 dest[4 * x + 3] = 0xFF;
414 }
415 }
416 else // L8 destination format
417 {
418 memcpy(dest, source, width);
419 }
420 }
421}
422
423void Image::loadLuminanceFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
424 int inputPitch, const void *input, size_t outputPitch, void *output) const
425{
426 const float *source = NULL;
427 float *dest = NULL;
428
429 for (int y = 0; y < height; y++)
430 {
431 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
432 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
433 for (int x = 0; x < width; x++)
434 {
435 dest[4 * x + 0] = source[x];
436 dest[4 * x + 1] = source[x];
437 dest[4 * x + 2] = source[x];
438 dest[4 * x + 3] = 1.0f;
439 }
440 }
441}
442
443void Image::loadLuminanceHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
444 int inputPitch, const void *input, size_t outputPitch, void *output) const
445{
446 const unsigned short *source = NULL;
447 unsigned short *dest = NULL;
448
449 for (int y = 0; y < height; y++)
450 {
451 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
452 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
453 for (int x = 0; x < width; x++)
454 {
455 dest[4 * x + 0] = source[x];
456 dest[4 * x + 1] = source[x];
457 dest[4 * x + 2] = source[x];
458 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
459 }
460 }
461}
462
463void Image::loadLuminanceAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
464 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
465{
466 const int destBytesPerPixel = native? 2: 4;
467 const unsigned char *source = NULL;
468 unsigned char *dest = NULL;
469
470 for (int y = 0; y < height; y++)
471 {
472 source = static_cast<const unsigned char*>(input) + y * inputPitch;
473 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
474
475 if (!native) // BGRA8 destination format
476 {
477 for (int x = 0; x < width; x++)
478 {
479 dest[4 * x + 0] = source[2*x+0];
480 dest[4 * x + 1] = source[2*x+0];
481 dest[4 * x + 2] = source[2*x+0];
482 dest[4 * x + 3] = source[2*x+1];
483 }
484 }
485 else
486 {
487 memcpy(dest, source, width * 2);
488 }
489 }
490}
491
492void Image::loadLuminanceAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
493 int inputPitch, const void *input, size_t outputPitch, void *output) const
494{
495 const float *source = NULL;
496 float *dest = NULL;
497
498 for (int y = 0; y < height; y++)
499 {
500 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
501 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
502 for (int x = 0; x < width; x++)
503 {
504 dest[4 * x + 0] = source[2*x+0];
505 dest[4 * x + 1] = source[2*x+0];
506 dest[4 * x + 2] = source[2*x+0];
507 dest[4 * x + 3] = source[2*x+1];
508 }
509 }
510}
511
512void Image::loadLuminanceAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
513 int inputPitch, const void *input, size_t outputPitch, void *output) const
514{
515 const unsigned short *source = NULL;
516 unsigned short *dest = NULL;
517
518 for (int y = 0; y < height; y++)
519 {
520 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
521 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
522 for (int x = 0; x < width; x++)
523 {
524 dest[4 * x + 0] = source[2*x+0];
525 dest[4 * x + 1] = source[2*x+0];
526 dest[4 * x + 2] = source[2*x+0];
527 dest[4 * x + 3] = source[2*x+1];
528 }
529 }
530}
531
532void Image::loadRGBUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
533 int inputPitch, const void *input, size_t outputPitch, void *output) const
534{
535 const unsigned char *source = NULL;
536 unsigned char *dest = NULL;
537
538 for (int y = 0; y < height; y++)
539 {
540 source = static_cast<const unsigned char*>(input) + y * inputPitch;
541 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
542 for (int x = 0; x < width; x++)
543 {
544 dest[4 * x + 0] = source[x * 3 + 2];
545 dest[4 * x + 1] = source[x * 3 + 1];
546 dest[4 * x + 2] = source[x * 3 + 0];
547 dest[4 * x + 3] = 0xFF;
548 }
549 }
550}
551
552void Image::loadRGB565Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
553 int inputPitch, const void *input, size_t outputPitch, void *output) const
554{
555 const unsigned short *source = NULL;
556 unsigned char *dest = NULL;
557
558 for (int y = 0; y < height; y++)
559 {
560 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
561 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
562 for (int x = 0; x < width; x++)
563 {
564 unsigned short rgba = source[x];
565 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
566 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
567 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
568 dest[4 * x + 3] = 0xFF;
569 }
570 }
571}
572
573void Image::loadRGBFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
574 int inputPitch, const void *input, size_t outputPitch, void *output) const
575{
576 const float *source = NULL;
577 float *dest = NULL;
578
579 for (int y = 0; y < height; y++)
580 {
581 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
582 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
583 for (int x = 0; x < width; x++)
584 {
585 dest[4 * x + 0] = source[x * 3 + 0];
586 dest[4 * x + 1] = source[x * 3 + 1];
587 dest[4 * x + 2] = source[x * 3 + 2];
588 dest[4 * x + 3] = 1.0f;
589 }
590 }
591}
592
593void Image::loadRGBHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
594 int inputPitch, const void *input, size_t outputPitch, void *output) const
595{
596 const unsigned short *source = NULL;
597 unsigned short *dest = NULL;
598
599 for (int y = 0; y < height; y++)
600 {
601 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
602 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
603 for (int x = 0; x < width; x++)
604 {
605 dest[4 * x + 0] = source[x * 3 + 0];
606 dest[4 * x + 1] = source[x * 3 + 1];
607 dest[4 * x + 2] = source[x * 3 + 2];
608 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
609 }
610 }
611}
612
613void Image::loadRGBAUByteDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
614 int inputPitch, const void *input, size_t outputPitch, void *output) const
615{
616 const unsigned int *source = NULL;
617 unsigned int *dest = NULL;
618 __m128i brMask = _mm_set1_epi32(0x00ff00ff);
619
620 for (int y = 0; y < height; y++)
621 {
622 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
623 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
624 int x = 0;
625
626 // Make output writes aligned
627 for (x = 0; ((reinterpret_cast<intptr_t>(&dest[x]) & 15) != 0) && x < width; x++)
628 {
629 unsigned int rgba = source[x];
630 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
631 }
632
633 for (; x + 3 < width; x += 4)
634 {
635 __m128i sourceData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&source[x]));
636 // Mask out g and a, which don't change
637 __m128i gaComponents = _mm_andnot_si128(brMask, sourceData);
638 // Mask out b and r
639 __m128i brComponents = _mm_and_si128(sourceData, brMask);
640 // Swap b and r
641 __m128i brSwapped = _mm_shufflehi_epi16(_mm_shufflelo_epi16(brComponents, _MM_SHUFFLE(2, 3, 0, 1)), _MM_SHUFFLE(2, 3, 0, 1));
642 __m128i result = _mm_or_si128(gaComponents, brSwapped);
643 _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), result);
644 }
645
646 // Perform leftover writes
647 for (; x < width; x++)
648 {
649 unsigned int rgba = source[x];
650 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
651 }
652 }
653}
654
655void Image::loadRGBAUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
656 int inputPitch, const void *input, size_t outputPitch, void *output) const
657{
658 const unsigned int *source = NULL;
659 unsigned int *dest = NULL;
660 for (int y = 0; y < height; y++)
661 {
662 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
663 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
664
665 for (int x = 0; x < width; x++)
666 {
667 unsigned int rgba = source[x];
668 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
669 }
670 }
671}
672
673void Image::loadRGBA4444Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
674 int inputPitch, const void *input, size_t outputPitch, void *output) const
675{
676 const unsigned short *source = NULL;
677 unsigned char *dest = NULL;
678
679 for (int y = 0; y < height; y++)
680 {
681 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
682 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
683 for (int x = 0; x < width; x++)
684 {
685 unsigned short rgba = source[x];
686 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
687 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
688 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
689 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
690 }
691 }
692}
693
694void Image::loadRGBA5551Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
695 int inputPitch, const void *input, size_t outputPitch, void *output) const
696{
697 const unsigned short *source = NULL;
698 unsigned char *dest = NULL;
699
700 for (int y = 0; y < height; y++)
701 {
702 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
703 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
704 for (int x = 0; x < width; x++)
705 {
706 unsigned short rgba = source[x];
707 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
708 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
709 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
710 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
711 }
712 }
713}
714
715void Image::loadRGBAFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
716 int inputPitch, const void *input, size_t outputPitch, void *output) const
717{
718 const float *source = NULL;
719 float *dest = NULL;
720
721 for (int y = 0; y < height; y++)
722 {
723 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
724 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
725 memcpy(dest, source, width * 16);
726 }
727}
728
729void Image::loadRGBAHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
730 int inputPitch, const void *input, size_t outputPitch, void *output) const
731{
732 const unsigned char *source = NULL;
733 unsigned char *dest = NULL;
734
735 for (int y = 0; y < height; y++)
736 {
737 source = static_cast<const unsigned char*>(input) + y * inputPitch;
738 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
739 memcpy(dest, source, width * 8);
740 }
741}
742
743void Image::loadBGRAData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
744 int inputPitch, const void *input, size_t outputPitch, void *output) const
745{
746 const unsigned char *source = NULL;
747 unsigned char *dest = NULL;
748
749 for (int y = 0; y < height; y++)
750 {
751 source = static_cast<const unsigned char*>(input) + y * inputPitch;
752 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
753 memcpy(dest, source, width*4);
754 }
755}
756
757void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
758 int inputPitch, const void *input, size_t outputPitch, void *output) const {
759 switch (getD3DFormat())
760 {
761 case D3DFMT_DXT1:
762 loadDXT1Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
763 break;
764 case D3DFMT_DXT3:
765 loadDXT3Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
766 break;
767 case D3DFMT_DXT5:
768 loadDXT5Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
769 break;
770 }
771}
772
773static void FlipCopyDXT1BlockFull(const unsigned int* source, unsigned int* dest) {
774 // A DXT1 block layout is:
775 // [0-1] color0.
776 // [2-3] color1.
777 // [4-7] color bitmap, 2 bits per pixel.
778 // So each of the 4-7 bytes represents one line, flipping a block is just
779 // flipping those bytes.
780
781 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
782 dest[0] = source[0];
783
784 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
785 dest[1] = (source[1] >> 24) |
786 ((source[1] << 8) & 0x00FF0000) |
787 ((source[1] >> 8) & 0x0000FF00) |
788 (source[1] << 24);
789}
790
791// Flips the first 2 lines of a DXT1 block in the y direction.
792static void FlipCopyDXT1BlockHalf(const unsigned int* source, unsigned int* dest) {
793 // See layout above.
794 dest[0] = source[0];
795 dest[1] = ((source[1] << 8) & 0x0000FF00) |
796 ((source[1] >> 8) & 0x000000FF);
797}
798
799// Flips a full DXT3 block in the y direction.
800static void FlipCopyDXT3BlockFull(const unsigned int* source, unsigned int* dest) {
801 // A DXT3 block layout is:
802 // [0-7] alpha bitmap, 4 bits per pixel.
803 // [8-15] a DXT1 block.
804
805 // First and Second 32 bits are 4bit per pixel alpha and need to be flipped.
806 dest[0] = (source[1] >> 16) | (source[1] << 16);
807 dest[1] = (source[0] >> 16) | (source[0] << 16);
808
809 // And flip the DXT1 block using the above function.
810 FlipCopyDXT1BlockFull(source + 2, dest + 2);
811}
812
813// Flips the first 2 lines of a DXT3 block in the y direction.
814static void FlipCopyDXT3BlockHalf(const unsigned int* source, unsigned int* dest) {
815 // See layout above.
816 dest[0] = (source[1] >> 16) | (source[1] << 16);
817 FlipCopyDXT1BlockHalf(source + 2, dest + 2);
818}
819
820// Flips a full DXT5 block in the y direction.
821static void FlipCopyDXT5BlockFull(const unsigned int* source, unsigned int* dest) {
822 // A DXT5 block layout is:
823 // [0] alpha0.
824 // [1] alpha1.
825 // [2-7] alpha bitmap, 3 bits per pixel.
826 // [8-15] a DXT1 block.
827
828 // The alpha bitmap doesn't easily map lines to bytes, so we have to
829 // interpret it correctly. Extracted from
830 // http://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt :
831 //
832 // The 6 "bits" bytes of the block are decoded into one 48-bit integer:
833 //
834 // bits = bits_0 + 256 * (bits_1 + 256 * (bits_2 + 256 * (bits_3 +
835 // 256 * (bits_4 + 256 * bits_5))))
836 //
837 // bits is a 48-bit unsigned integer, from which a three-bit control code
838 // is extracted for a texel at location (x,y) in the block using:
839 //
840 // code(x,y) = bits[3*(4*y+x)+1..3*(4*y+x)+0]
841 //
842 // where bit 47 is the most significant and bit 0 is the least
843 // significant bit.
844 const unsigned char* sourceBytes = static_cast<const unsigned char*>(static_cast<const void*>(source));
845 unsigned char* destBytes = static_cast<unsigned char*>(static_cast<void*>(dest));
846 unsigned int line_0_1 = sourceBytes[2] + 256 * (sourceBytes[3] + 256 * sourceBytes[4]);
847 unsigned int line_2_3 = sourceBytes[5] + 256 * (sourceBytes[6] + 256 * sourceBytes[7]);
848 // swap lines 0 and 1 in line_0_1.
849 unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) |
850 ((line_0_1 & 0xfff000) >> 12);
851 // swap lines 2 and 3 in line_2_3.
852 unsigned int line_3_2 = ((line_2_3 & 0x000fff) << 12) |
853 ((line_2_3 & 0xfff000) >> 12);
854 destBytes[0] = sourceBytes[0];
855 destBytes[1] = sourceBytes[1];
856 destBytes[2] = line_3_2 & 0xff;
857 destBytes[3] = (line_3_2 & 0xff00) >> 8;
858 destBytes[4] = (line_3_2 & 0xff0000) >> 16;
859 destBytes[5] = line_1_0 & 0xff;
860 destBytes[6] = (line_1_0 & 0xff00) >> 8;
861 destBytes[7] = (line_1_0 & 0xff0000) >> 16;
862
863 // And flip the DXT1 block using the above function.
864 FlipCopyDXT1BlockFull(source + 2, dest + 2);
865}
866
867// Flips the first 2 lines of a DXT5 block in the y direction.
868static void FlipCopyDXT5BlockHalf(const unsigned int* source, unsigned int* dest) {
869 // See layout above.
870 const unsigned char* sourceBytes = static_cast<const unsigned char*>(static_cast<const void*>(source));
871 unsigned char* destBytes = static_cast<unsigned char*>(static_cast<void*>(dest));
872 unsigned int line_0_1 = sourceBytes[2] + 256 * (sourceBytes[3] + 256 * sourceBytes[4]);
873 unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) |
874 ((line_0_1 & 0xfff000) >> 12);
875 destBytes[0] = sourceBytes[0];
876 destBytes[1] = sourceBytes[1];
877 destBytes[2] = line_1_0 & 0xff;
878 destBytes[3] = (line_1_0 & 0xff00) >> 8;
879 destBytes[4] = (line_1_0 & 0xff0000) >> 16;
880 FlipCopyDXT1BlockHalf(source + 2, dest + 2);
881}
882
883void Image::loadDXT1Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
884 int inputPitch, const void *input, size_t outputPitch, void *output) const
885{
886 ASSERT(xoffset % 4 == 0);
887 ASSERT(yoffset % 4 == 0);
888 ASSERT(width % 4 == 0 || width == 2 || width == 1);
889 ASSERT(inputPitch % 8 == 0);
890 ASSERT(outputPitch % 8 == 0);
891
892 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
893 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
894
895 // Round width up in case it is less than 4.
896 int blocksAcross = (width + 3) / 4;
897 int intsAcross = blocksAcross * 2;
898
899 switch (height)
900 {
901 case 1:
902 for (int x = 0; x < intsAcross; x += 2)
903 {
904 // just copy the block
905 dest[x] = source[x];
906 dest[x + 1] = source[x + 1];
907 }
908 break;
909 case 2:
910 for (int x = 0; x < intsAcross; x += 2)
911 {
912 FlipCopyDXT1BlockHalf(source + x, dest + x);
913 }
914 break;
915 default:
916 ASSERT(height % 4 == 0);
917 for (int y = 0; y < height / 4; ++y)
918 {
919 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
920 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
921
922 for (int x = 0; x < intsAcross; x += 2)
923 {
924 FlipCopyDXT1BlockFull(source + x, dest + x);
925 }
926 }
927 break;
928 }
929}
930
931void Image::loadDXT3Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
932 int inputPitch, const void *input, size_t outputPitch, void *output) const
933{
934 ASSERT(xoffset % 4 == 0);
935 ASSERT(yoffset % 4 == 0);
936 ASSERT(width % 4 == 0 || width == 2 || width == 1);
937 ASSERT(inputPitch % 16 == 0);
938 ASSERT(outputPitch % 16 == 0);
939
940 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
941 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
942
943 // Round width up in case it is less than 4.
944 int blocksAcross = (width + 3) / 4;
945 int intsAcross = blocksAcross * 4;
946
947 switch (height)
948 {
949 case 1:
950 for (int x = 0; x < intsAcross; x += 4)
951 {
952 // just copy the block
953 dest[x] = source[x];
954 dest[x + 1] = source[x + 1];
955 dest[x + 2] = source[x + 2];
956 dest[x + 3] = source[x + 3];
957 }
958 break;
959 case 2:
960 for (int x = 0; x < intsAcross; x += 4)
961 {
962 FlipCopyDXT3BlockHalf(source + x, dest + x);
963 }
964 break;
965 default:
966 ASSERT(height % 4 == 0);
967 for (int y = 0; y < height / 4; ++y)
968 {
969 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
970 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
971
972 for (int x = 0; x < intsAcross; x += 4)
973 {
974 FlipCopyDXT3BlockFull(source + x, dest + x);
975 }
976 }
977 break;
978 }
979}
980
981void Image::loadDXT5Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
982 int inputPitch, const void *input, size_t outputPitch, void *output) const
983{
984 ASSERT(xoffset % 4 == 0);
985 ASSERT(yoffset % 4 == 0);
986 ASSERT(width % 4 == 0 || width == 2 || width == 1);
987 ASSERT(inputPitch % 16 == 0);
988 ASSERT(outputPitch % 16 == 0);
989
990 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
991 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
992
993 // Round width up in case it is less than 4.
994 int blocksAcross = (width + 3) / 4;
995 int intsAcross = blocksAcross * 4;
996
997 switch (height)
998 {
999 case 1:
1000 for (int x = 0; x < intsAcross; x += 4)
1001 {
1002 // just copy the block
1003 dest[x] = source[x];
1004 dest[x + 1] = source[x + 1];
1005 dest[x + 2] = source[x + 2];
1006 dest[x + 3] = source[x + 3];
1007 }
1008 break;
1009 case 2:
1010 for (int x = 0; x < intsAcross; x += 4)
1011 {
1012 FlipCopyDXT5BlockHalf(source + x, dest + x);
1013 }
1014 break;
1015 default:
1016 ASSERT(height % 4 == 0);
1017 for (int y = 0; y < height / 4; ++y)
1018 {
1019 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
1020 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
1021
1022 for (int x = 0; x < intsAcross; x += 4)
1023 {
1024 FlipCopyDXT5BlockFull(source + x, dest + x);
1025 }
1026 }
1027 break;
1028 }
1029}
1030
daniel@transgaming.com90cfcc92011-11-09 17:45:48 +00001031// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
1032void Image::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
1033{
1034 IDirect3DDevice9 *device = getDevice();
1035 IDirect3DSurface9 *renderTargetData = NULL;
1036 D3DSURFACE_DESC description;
1037 renderTarget->GetDesc(&description);
1038
1039 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
1040
1041 if (FAILED(result))
1042 {
1043 ERR("Could not create matching destination surface.");
1044 return error(GL_OUT_OF_MEMORY);
1045 }
1046
1047 result = device->GetRenderTargetData(renderTarget, renderTargetData);
1048
1049 if (FAILED(result))
1050 {
1051 ERR("GetRenderTargetData unexpectedly failed.");
1052 renderTargetData->Release();
1053 return error(GL_OUT_OF_MEMORY);
1054 }
1055
1056 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
1057 int destYOffset = transformPixelYOffset(yoffset, height, mHeight);
1058 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
1059
1060 if (isRenderable())
1061 {
1062 result = D3DXLoadSurfaceFromSurface(getSurface(), NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0);
1063
1064 if (FAILED(result))
1065 {
1066 ERR("Copying surfaces unexpectedly failed.");
1067 renderTargetData->Release();
1068 return error(GL_OUT_OF_MEMORY);
1069 }
1070 }
1071 else
1072 {
1073 D3DLOCKED_RECT sourceLock = {0};
1074 result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
1075
1076 if (FAILED(result))
1077 {
1078 ERR("Failed to lock the source surface (rectangle might be invalid).");
1079 renderTargetData->Release();
1080 return error(GL_OUT_OF_MEMORY);
1081 }
1082
1083 D3DLOCKED_RECT destLock = {0};
1084 result = lock(&destLock, &destRect);
1085
1086 if (FAILED(result))
1087 {
1088 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1089 renderTargetData->UnlockRect();
1090 renderTargetData->Release();
1091 return error(GL_OUT_OF_MEMORY);
1092 }
1093
1094 if (destLock.pBits && sourceLock.pBits)
1095 {
1096 unsigned char *source = (unsigned char*)sourceLock.pBits;
1097 unsigned char *dest = (unsigned char*)destLock.pBits;
1098
1099 switch (description.Format)
1100 {
1101 case D3DFMT_X8R8G8B8:
1102 case D3DFMT_A8R8G8B8:
1103 switch(getD3DFormat())
1104 {
1105 case D3DFMT_L8:
1106 for(int y = 0; y < height; y++)
1107 {
1108 for(int x = 0; x < width; x++)
1109 {
1110 dest[x] = source[x * 4 + 2];
1111 }
1112
1113 source += sourceLock.Pitch;
1114 dest += destLock.Pitch;
1115 }
1116 break;
1117 case D3DFMT_A8L8:
1118 for(int y = 0; y < height; y++)
1119 {
1120 for(int x = 0; x < width; x++)
1121 {
1122 dest[x * 2 + 0] = source[x * 4 + 2];
1123 dest[x * 2 + 1] = source[x * 4 + 3];
1124 }
1125
1126 source += sourceLock.Pitch;
1127 dest += destLock.Pitch;
1128 }
1129 break;
1130 default:
1131 UNREACHABLE();
1132 }
1133 break;
1134 case D3DFMT_R5G6B5:
1135 switch(getD3DFormat())
1136 {
1137 case D3DFMT_L8:
1138 for(int y = 0; y < height; y++)
1139 {
1140 for(int x = 0; x < width; x++)
1141 {
1142 unsigned char red = source[x * 2 + 1] & 0xF8;
1143 dest[x] = red | (red >> 5);
1144 }
1145
1146 source += sourceLock.Pitch;
1147 dest += destLock.Pitch;
1148 }
1149 break;
1150 default:
1151 UNREACHABLE();
1152 }
1153 break;
1154 case D3DFMT_A1R5G5B5:
1155 switch(getD3DFormat())
1156 {
1157 case D3DFMT_L8:
1158 for(int y = 0; y < height; y++)
1159 {
1160 for(int x = 0; x < width; x++)
1161 {
1162 unsigned char red = source[x * 2 + 1] & 0x7C;
1163 dest[x] = (red << 1) | (red >> 4);
1164 }
1165
1166 source += sourceLock.Pitch;
1167 dest += destLock.Pitch;
1168 }
1169 break;
1170 case D3DFMT_A8L8:
1171 for(int y = 0; y < height; y++)
1172 {
1173 for(int x = 0; x < width; x++)
1174 {
1175 unsigned char red = source[x * 2 + 1] & 0x7C;
1176 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1177 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1178 }
1179
1180 source += sourceLock.Pitch;
1181 dest += destLock.Pitch;
1182 }
1183 break;
1184 default:
1185 UNREACHABLE();
1186 }
1187 break;
1188 default:
1189 UNREACHABLE();
1190 }
1191 }
1192
1193 unlock();
1194 renderTargetData->UnlockRect();
1195 }
1196
1197 renderTargetData->Release();
1198
1199 mDirty = true;
1200}
1201
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00001202Texture::Texture(GLuint id) : RefCountObject(id)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001203{
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00001204 mSerial = 0;
1205
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001206 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
1207 mMagFilter = GL_LINEAR;
1208 mWrapS = GL_REPEAT;
1209 mWrapT = GL_REPEAT;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001210 mDirtyParameters = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001211
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001212 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001213
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001214 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001215}
1216
1217Texture::~Texture()
1218{
1219}
1220
1221Blit *Texture::getBlitter()
1222{
1223 Context *context = getContext();
1224 return context->getBlitter();
1225}
1226
1227// Returns true on successful filter state update (valid enum parameter)
1228bool Texture::setMinFilter(GLenum filter)
1229{
1230 switch (filter)
1231 {
1232 case GL_NEAREST:
1233 case GL_LINEAR:
1234 case GL_NEAREST_MIPMAP_NEAREST:
1235 case GL_LINEAR_MIPMAP_NEAREST:
1236 case GL_NEAREST_MIPMAP_LINEAR:
1237 case GL_LINEAR_MIPMAP_LINEAR:
1238 {
1239 if (mMinFilter != filter)
1240 {
1241 mMinFilter = filter;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001242 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001243 }
1244 return true;
1245 }
1246 default:
1247 return false;
1248 }
1249}
1250
1251// Returns true on successful filter state update (valid enum parameter)
1252bool Texture::setMagFilter(GLenum filter)
1253{
1254 switch (filter)
1255 {
1256 case GL_NEAREST:
1257 case GL_LINEAR:
1258 {
1259 if (mMagFilter != filter)
1260 {
1261 mMagFilter = filter;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001262 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001263 }
1264 return true;
1265 }
1266 default:
1267 return false;
1268 }
1269}
1270
1271// Returns true on successful wrap state update (valid enum parameter)
1272bool Texture::setWrapS(GLenum wrap)
1273{
1274 switch (wrap)
1275 {
1276 case GL_REPEAT:
1277 case GL_CLAMP_TO_EDGE:
1278 case GL_MIRRORED_REPEAT:
1279 {
1280 if (mWrapS != wrap)
1281 {
1282 mWrapS = wrap;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001283 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001284 }
1285 return true;
1286 }
1287 default:
1288 return false;
1289 }
1290}
1291
1292// Returns true on successful wrap state update (valid enum parameter)
1293bool Texture::setWrapT(GLenum wrap)
1294{
1295 switch (wrap)
1296 {
1297 case GL_REPEAT:
1298 case GL_CLAMP_TO_EDGE:
1299 case GL_MIRRORED_REPEAT:
1300 {
1301 if (mWrapT != wrap)
1302 {
1303 mWrapT = wrap;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001304 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001305 }
1306 return true;
1307 }
1308 default:
1309 return false;
1310 }
1311}
1312
1313GLenum Texture::getMinFilter() const
1314{
1315 return mMinFilter;
1316}
1317
1318GLenum Texture::getMagFilter() const
1319{
1320 return mMagFilter;
1321}
1322
1323GLenum Texture::getWrapS() const
1324{
1325 return mWrapS;
1326}
1327
1328GLenum Texture::getWrapT() const
1329{
1330 return mWrapT;
1331}
1332
daniel@transgaming.com61208202011-03-21 16:38:50 +00001333void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001334{
daniel@transgaming.com73de05a2011-11-09 17:45:24 +00001335 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001336 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001337 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001338 HRESULT result = image->lock(&locked, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001339
1340 if (SUCCEEDED(result))
1341 {
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +00001342 image->loadData(0, 0, image->getWidth(), image->getHeight(), image->getType(), unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001343 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001344 }
1345
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001346 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001347 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001348}
1349
daniel@transgaming.com61208202011-03-21 16:38:50 +00001350void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001351{
daniel@transgaming.com73de05a2011-11-09 17:45:24 +00001352 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001353 {
1354 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001355 HRESULT result = image->lock(&locked, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001356
1357 if (SUCCEEDED(result))
1358 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001359 int inputPitch = ComputeCompressedPitch(image->getWidth(), image->getFormat());
1360 int inputSize = ComputeCompressedSize(image->getWidth(), image->getHeight(), image->getFormat());
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +00001361 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 +00001362 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001363 }
1364
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001365 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001366 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001367}
1368
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001369bool 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 +00001370{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001371 if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001372 {
1373 error(GL_INVALID_VALUE);
1374 return false;
1375 }
1376
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001377 if (IsCompressed(image->getFormat()))
jbauman@chromium.orge2f954c2011-05-03 20:45:27 +00001378 {
1379 error(GL_INVALID_OPERATION);
1380 return false;
1381 }
1382
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001383 if (format != image->getFormat())
jbauman@chromium.orge2f954c2011-05-03 20:45:27 +00001384 {
1385 error(GL_INVALID_OPERATION);
1386 return false;
1387 }
1388
daniel@transgaming.com73de05a2011-11-09 17:45:24 +00001389 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001390 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001391 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001392 HRESULT result = image->lock(&locked, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001393
1394 if (SUCCEEDED(result))
1395 {
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +00001396 image->loadData(xoffset, transformPixelYOffset(yoffset, height, image->getHeight()), width, height, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001397 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001398 }
1399
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001400 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001401 }
1402
1403 return true;
1404}
1405
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001406bool 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 +00001407{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001408 if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001409 {
1410 error(GL_INVALID_VALUE);
1411 return false;
1412 }
1413
1414 if (format != getInternalFormat())
1415 {
1416 error(GL_INVALID_OPERATION);
1417 return false;
1418 }
1419
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001420 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001421 {
1422 RECT updateRegion;
1423 updateRegion.left = xoffset;
1424 updateRegion.right = xoffset + width;
1425 updateRegion.bottom = yoffset + height;
1426 updateRegion.top = yoffset;
1427
1428 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001429 HRESULT result = image->lock(&locked, &updateRegion);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001430
1431 if (SUCCEEDED(result))
1432 {
1433 int inputPitch = ComputeCompressedPitch(width, format);
1434 int inputSize = ComputeCompressedSize(width, height, format);
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +00001435 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 +00001436 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001437 }
1438
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001439 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001440 }
1441
1442 return true;
1443}
1444
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001445IDirect3DBaseTexture9 *Texture::getTexture()
1446{
1447 if (!isComplete())
1448 {
1449 return NULL;
1450 }
1451
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001452 if (!getBaseTexture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001453 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001454 createTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001455 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001456
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +00001457 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001458
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001459 return getBaseTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001460}
1461
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001462bool Texture::hasDirtyParameters() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001463{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001464 return mDirtyParameters;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001465}
1466
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001467bool Texture::hasDirtyImages() const
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001468{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001469 return mDirtyImages;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001470}
1471
1472void Texture::resetDirty()
1473{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001474 mDirtyParameters = false;
1475 mDirtyImages = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001476}
1477
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001478unsigned int Texture::getSerial() const
1479{
1480 return mSerial;
1481}
1482
daniel@transgaming.comf81103a2011-11-09 17:46:28 +00001483GLint Texture::creationLevels(GLsizei width, GLsizei height) const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001484{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001485 if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001486 {
daniel@transgaming.comf81103a2011-11-09 17:46:28 +00001487 return 0; // Maximum number of levels
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001488 }
1489 else
1490 {
1491 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1492 return 1;
1493 }
1494}
1495
daniel@transgaming.comf81103a2011-11-09 17:46:28 +00001496GLint Texture::creationLevels(GLsizei size) const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001497{
daniel@transgaming.comf81103a2011-11-09 17:46:28 +00001498 return creationLevels(size, size);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001499}
1500
1501int Texture::levelCount() const
1502{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001503 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001504}
1505
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001506unsigned int Texture::issueSerial()
1507{
1508 return mCurrentSerial++;
1509}
1510
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001511Texture2D::Texture2D(GLuint id) : Texture(id)
1512{
1513 mTexture = NULL;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001514 mSurface = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001515}
1516
1517Texture2D::~Texture2D()
1518{
1519 mColorbufferProxy.set(NULL);
1520
1521 if (mTexture)
1522 {
1523 mTexture->Release();
1524 mTexture = NULL;
1525 }
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001526
1527 if (mSurface)
1528 {
1529 mSurface->setBoundTexture(NULL);
1530 mSurface = NULL;
1531 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001532}
1533
1534GLenum Texture2D::getTarget() const
1535{
1536 return GL_TEXTURE_2D;
1537}
1538
daniel@transgaming.com61208202011-03-21 16:38:50 +00001539GLsizei Texture2D::getWidth() const
1540{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001541 return mImageArray[0].getWidth();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001542}
1543
1544GLsizei Texture2D::getHeight() const
1545{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001546 return mImageArray[0].getHeight();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001547}
1548
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001549GLenum Texture2D::getInternalFormat() const
1550{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001551 return mImageArray[0].getFormat();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001552}
1553
daniel@transgaming.com61208202011-03-21 16:38:50 +00001554GLenum Texture2D::getType() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001555{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001556 return mImageArray[0].getType();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001557}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001558
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001559D3DFORMAT Texture2D::getD3DFormat() const
1560{
1561 return mImageArray[0].getD3DFormat();
1562}
1563
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001564void Texture2D::redefineImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.com61208202011-03-21 16:38:50 +00001565{
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001566 releaseTexImage();
1567
daniel@transgaming.com41634052011-11-09 17:46:24 +00001568 bool redefined = mImageArray[level].redefine(format, width, height, type);
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00001569
daniel@transgaming.com41634052011-11-09 17:46:24 +00001570 if (mTexture && redefined)
daniel@transgaming.com61208202011-03-21 16:38:50 +00001571 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001572 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1573 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001574 mImageArray[i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001575 }
1576
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001577 mTexture->Release();
1578 mTexture = NULL;
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00001579 mSerial = 0;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001580 mDirtyImages = true;
apatrick@chromium.org57a2cd62011-06-08 00:04:07 +00001581 mColorbufferProxy.set(NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001582 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001583}
1584
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001585void 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 +00001586{
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001587 redefineImage(level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001588
daniel@transgaming.com61208202011-03-21 16:38:50 +00001589 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001590}
1591
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001592void Texture2D::bindTexImage(egl::Surface *surface)
1593{
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001594 releaseTexImage();
1595
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001596 GLenum format;
1597
1598 switch(surface->getFormat())
1599 {
1600 case D3DFMT_A8R8G8B8:
1601 format = GL_RGBA;
1602 break;
1603 case D3DFMT_X8R8G8B8:
1604 format = GL_RGB;
1605 break;
1606 default:
1607 UNIMPLEMENTED();
1608 return;
1609 }
1610
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001611 mImageArray[0].redefine(format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE);
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001612
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001613 mTexture = surface->getOffscreenTexture();
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00001614 mSerial = issueSerial();
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00001615 mColorbufferProxy.set(NULL);
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001616 mDirtyImages = true;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001617 mIsRenderable = true;
1618 mSurface = surface;
1619 mSurface->setBoundTexture(this);
1620}
1621
1622void Texture2D::releaseTexImage()
1623{
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001624 if (mSurface)
1625 {
1626 mSurface->setBoundTexture(NULL);
1627 mSurface = NULL;
1628
1629 if (mTexture)
1630 {
1631 mTexture->Release();
1632 mTexture = NULL;
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00001633 mSerial = 0;
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00001634 mColorbufferProxy.set(NULL);
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001635 }
1636
1637 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1638 {
1639 mImageArray[i].redefine(GL_RGBA, 0, 0, GL_UNSIGNED_BYTE);
1640 }
1641 }
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001642}
1643
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001644void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001645{
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001646 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001647
daniel@transgaming.com61208202011-03-21 16:38:50 +00001648 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001649}
1650
1651void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1652{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001653 ASSERT(mImageArray[level].getSurface() != NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001654
1655 if (level < levelCount())
1656 {
1657 IDirect3DSurface9 *destLevel = NULL;
1658 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1659
1660 ASSERT(SUCCEEDED(result));
1661
1662 if (SUCCEEDED(result))
1663 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001664 Image *image = &mImageArray[level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001665
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001666 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->getHeight());;
daniel@transgaming.comb612f882011-11-09 17:44:31 +00001667 POINT destPoint = {sourceRect.left, sourceRect.top};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001668
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001669 result = getDevice()->UpdateSurface(image->getSurface(), &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001670 ASSERT(SUCCEEDED(result));
1671
1672 destLevel->Release();
1673
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001674 image->markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001675 }
1676 }
1677}
1678
1679void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1680{
1681 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1682 {
1683 commitRect(level, xoffset, yoffset, width, height);
1684 }
1685}
1686
1687void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1688{
1689 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1690 {
1691 commitRect(level, xoffset, yoffset, width, height);
1692 }
1693}
1694
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001695void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001696{
1697 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1698
1699 if (!renderTarget)
1700 {
1701 ERR("Failed to retrieve the render target.");
1702 return error(GL_OUT_OF_MEMORY);
1703 }
1704
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001705 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001706
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001707 if (!mImageArray[level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001708 {
daniel@transgaming.com90cfcc92011-11-09 17:45:48 +00001709 mImageArray[level].copy(0, 0, x, y, width, height, renderTarget);
1710 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001711 }
1712 else
1713 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001714 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001715 {
1716 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001717 }
daniel@transgaming.com3b3c1d42011-06-08 20:38:09 +00001718
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001719 mImageArray[level].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001720
1721 if (width != 0 && height != 0 && level < levelCount())
1722 {
1723 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1724 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1725 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1726 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1727 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001728
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001729 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[level].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001730
1731 IDirect3DSurface9 *dest;
1732 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1733
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001734 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001735 dest->Release();
1736 }
1737 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001738}
1739
1740void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1741{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001742 if (xoffset + width > mImageArray[level].getWidth() || yoffset + height > mImageArray[level].getHeight())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001743 {
1744 return error(GL_INVALID_VALUE);
1745 }
1746
1747 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1748
1749 if (!renderTarget)
1750 {
1751 ERR("Failed to retrieve the render target.");
1752 return error(GL_OUT_OF_MEMORY);
1753 }
1754
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001755 if (!mImageArray[level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001756 {
daniel@transgaming.com90cfcc92011-11-09 17:45:48 +00001757 mImageArray[level].copy(xoffset, yoffset, x, y, width, height, renderTarget);
1758 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001759 }
1760 else
1761 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001762 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001763 {
1764 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001765 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001766
1767 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001768
1769 if (level < levelCount())
1770 {
1771 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1772 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1773 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1774 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1775 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1776
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001777 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001778
1779 IDirect3DSurface9 *dest;
1780 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1781
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001782 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0].getFormat(), xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001783 dest->Release();
1784 }
1785 }
1786}
1787
1788// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1789bool Texture2D::isComplete() const
1790{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001791 GLsizei width = mImageArray[0].getWidth();
1792 GLsizei height = mImageArray[0].getHeight();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001793
1794 if (width <= 0 || height <= 0)
1795 {
1796 return false;
1797 }
1798
1799 bool mipmapping = false;
1800
1801 switch (mMinFilter)
1802 {
1803 case GL_NEAREST:
1804 case GL_LINEAR:
1805 mipmapping = false;
1806 break;
1807 case GL_NEAREST_MIPMAP_NEAREST:
1808 case GL_LINEAR_MIPMAP_NEAREST:
1809 case GL_NEAREST_MIPMAP_LINEAR:
1810 case GL_LINEAR_MIPMAP_LINEAR:
1811 mipmapping = true;
1812 break;
1813 default: UNREACHABLE();
1814 }
1815
daniel@transgaming.combbeffbb2011-11-09 17:46:11 +00001816 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) ||
1817 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsFloat16LinearFilter()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001818 {
1819 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1820 {
1821 return false;
1822 }
1823 }
1824
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001825 bool npot = getContext()->supportsNonPower2Texture();
1826
1827 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001828 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001829 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
1830 (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1831 {
1832 return false;
1833 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001834 }
1835
1836 if (mipmapping)
1837 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001838 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001839 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001840 if (!isPow2(width) || !isPow2(height))
1841 {
1842 return false;
1843 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001844 }
1845
1846 int q = log2(std::max(width, height));
1847
1848 for (int level = 1; level <= q; level++)
1849 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001850 if (mImageArray[level].getFormat() != mImageArray[0].getFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001851 {
1852 return false;
1853 }
1854
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001855 if (mImageArray[level].getType() != mImageArray[0].getType())
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001856 {
1857 return false;
1858 }
1859
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001860 if (mImageArray[level].getWidth() != std::max(1, width >> level))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001861 {
1862 return false;
1863 }
1864
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001865 if (mImageArray[level].getHeight() != std::max(1, height >> level))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001866 {
1867 return false;
1868 }
1869 }
1870 }
1871
1872 return true;
1873}
1874
1875bool Texture2D::isCompressed() const
1876{
1877 return IsCompressed(getInternalFormat());
1878}
1879
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001880IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1881{
1882 return mTexture;
1883}
1884
1885// Constructs a Direct3D 9 texture resource from the texture images
1886void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001887{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001888 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001889 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.comf81103a2011-11-09 17:46:28 +00001890 GLint levels = creationLevels(mImageArray[0].getWidth(), mImageArray[0].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001891
daniel@transgaming.com61208202011-03-21 16:38:50 +00001892 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001893 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 +00001894
1895 if (FAILED(result))
1896 {
1897 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001898 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001899 }
1900
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001901 if (mTexture)
1902 {
1903 mTexture->Release();
1904 }
1905
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001906 mTexture = texture;
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00001907 mSerial = issueSerial();
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00001908 mColorbufferProxy.set(NULL);
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001909 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001910 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001911}
1912
1913void Texture2D::updateTexture()
1914{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001915 int levels = levelCount();
1916
1917 for (int level = 0; level < levels; level++)
1918 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00001919 Image *image = &mImageArray[level];
1920
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001921 if (image->isDirty())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001922 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001923 commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001924 }
1925 }
1926}
1927
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001928void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001929{
1930 IDirect3DTexture9 *texture = NULL;
1931
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001932 if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001933 {
1934 egl::Display *display = getDisplay();
1935 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001936 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.comf81103a2011-11-09 17:46:28 +00001937 GLint levels = creationLevels(mImageArray[0].getWidth(), mImageArray[0].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001938
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001939 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 +00001940
1941 if (FAILED(result))
1942 {
1943 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001944 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001945 }
1946
1947 if (mTexture != NULL)
1948 {
1949 int levels = levelCount();
1950 for (int i = 0; i < levels; i++)
1951 {
1952 IDirect3DSurface9 *source;
1953 result = mTexture->GetSurfaceLevel(i, &source);
1954
1955 if (FAILED(result))
1956 {
1957 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1958
1959 texture->Release();
1960
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001961 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001962 }
1963
1964 IDirect3DSurface9 *dest;
1965 result = texture->GetSurfaceLevel(i, &dest);
1966
1967 if (FAILED(result))
1968 {
1969 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1970
1971 texture->Release();
1972 source->Release();
1973
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001974 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001975 }
1976
1977 display->endScene();
1978 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1979
1980 if (FAILED(result))
1981 {
1982 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1983
1984 texture->Release();
1985 source->Release();
1986 dest->Release();
1987
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001988 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001989 }
1990
1991 source->Release();
1992 dest->Release();
1993 }
1994 }
1995 }
1996
1997 if (mTexture != NULL)
1998 {
1999 mTexture->Release();
2000 }
2001
2002 mTexture = texture;
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00002003 mSerial = issueSerial();
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00002004 mColorbufferProxy.set(NULL);
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002005 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002006 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002007}
2008
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002009void Texture2D::generateMipmaps()
2010{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002011 if (!getContext()->supportsNonPower2Texture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002012 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002013 if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight()))
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002014 {
2015 return error(GL_INVALID_OPERATION);
2016 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002017 }
2018
2019 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002020 unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight()));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002021 for (unsigned int i = 1; i <= q; i++)
2022 {
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00002023 redefineImage(i, mImageArray[0].getFormat(),
2024 std::max(mImageArray[0].getWidth() >> i, 1),
2025 std::max(mImageArray[0].getHeight() >> i, 1),
2026 mImageArray[0].getType());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002027 }
2028
daniel@transgaming.com9d4eac72011-11-09 17:45:53 +00002029 if (mTexture && mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002030 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002031 for (unsigned int i = 1; i <= q; i++)
2032 {
2033 IDirect3DSurface9 *upper = NULL;
2034 IDirect3DSurface9 *lower = NULL;
2035
2036 mTexture->GetSurfaceLevel(i-1, &upper);
2037 mTexture->GetSurfaceLevel(i, &lower);
2038
2039 if (upper != NULL && lower != NULL)
2040 {
2041 getBlitter()->boxFilter(upper, lower);
2042 }
2043
2044 if (upper != NULL) upper->Release();
2045 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002046
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002047 mImageArray[i].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002048 }
2049 }
2050 else
2051 {
2052 for (unsigned int i = 1; i <= q; i++)
2053 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002054 if (mImageArray[i].getSurface() == NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002055 {
2056 return error(GL_OUT_OF_MEMORY);
2057 }
2058
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002059 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 +00002060 {
2061 ERR(" failed to load filter %d to %d.", i - 1, i);
2062 }
2063
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002064 mImageArray[i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002065 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002066 }
2067}
2068
2069Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
2070{
2071 if (target != GL_TEXTURE_2D)
2072 {
2073 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2074 }
2075
2076 if (mColorbufferProxy.get() == NULL)
2077 {
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00002078 mColorbufferProxy.set(new Renderbuffer(id(), new RenderbufferTexture(this, target)));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002079 }
2080
2081 return mColorbufferProxy.get();
2082}
2083
2084IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
2085{
2086 ASSERT(target == GL_TEXTURE_2D);
2087
daniel@transgaming.com9d4eac72011-11-09 17:45:53 +00002088 if (!mTexture || !mIsRenderable)
daniel@transgaming.com61208202011-03-21 16:38:50 +00002089 {
2090 convertToRenderTarget();
2091 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002092
2093 if (mTexture == NULL)
2094 {
2095 return NULL;
2096 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002097
2098 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002099
2100 IDirect3DSurface9 *renderTarget = NULL;
2101 mTexture->GetSurfaceLevel(0, &renderTarget);
2102
2103 return renderTarget;
2104}
2105
2106TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
2107{
2108 mTexture = NULL;
2109}
2110
2111TextureCubeMap::~TextureCubeMap()
2112{
2113 for (int i = 0; i < 6; i++)
2114 {
2115 mFaceProxies[i].set(NULL);
2116 }
2117
2118 if (mTexture)
2119 {
2120 mTexture->Release();
2121 mTexture = NULL;
2122 }
2123}
2124
2125GLenum TextureCubeMap::getTarget() const
2126{
2127 return GL_TEXTURE_CUBE_MAP;
2128}
2129
daniel@transgaming.com61208202011-03-21 16:38:50 +00002130GLsizei TextureCubeMap::getWidth() const
2131{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002132 return mImageArray[0][0].getWidth();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002133}
2134
2135GLsizei TextureCubeMap::getHeight() const
2136{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002137 return mImageArray[0][0].getHeight();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002138}
2139
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002140GLenum TextureCubeMap::getInternalFormat() const
2141{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002142 return mImageArray[0][0].getFormat();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002143}
2144
daniel@transgaming.com61208202011-03-21 16:38:50 +00002145GLenum TextureCubeMap::getType() const
2146{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002147 return mImageArray[0][0].getType();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002148}
2149
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002150D3DFORMAT TextureCubeMap::getD3DFormat() const
2151{
2152 return mImageArray[0][0].getD3DFormat();
2153}
2154
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002155void 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 +00002156{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002157 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002158}
2159
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002160void 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 +00002161{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002162 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002163}
2164
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002165void 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 +00002166{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002167 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002168}
2169
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002170void 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 +00002171{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002172 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002173}
2174
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002175void 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 +00002176{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002177 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002178}
2179
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002180void 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 +00002181{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002182 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002183}
2184
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002185void 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 +00002186{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002187 redefineImage(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002188
daniel@transgaming.com61208202011-03-21 16:38:50 +00002189 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002190}
2191
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002192void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002193{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002194 ASSERT(mImageArray[face][level].getSurface() != NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002195
2196 if (level < levelCount())
2197 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002198 IDirect3DSurface9 *destLevel = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002199 ASSERT(destLevel != NULL);
2200
2201 if (destLevel != NULL)
2202 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002203 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002204
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002205 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->getHeight());;
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002206 POINT destPoint = {sourceRect.left, sourceRect.top};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002207
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002208 HRESULT result = getDevice()->UpdateSurface(image->getSurface(), &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002209 ASSERT(SUCCEEDED(result));
2210
2211 destLevel->Release();
2212
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002213 image->markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002214 }
2215 }
2216}
2217
2218void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2219{
2220 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
2221 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002222 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002223 }
2224}
2225
2226void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
2227{
2228 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
2229 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002230 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002231 }
2232}
2233
2234// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
2235bool TextureCubeMap::isComplete() const
2236{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002237 int size = mImageArray[0][0].getWidth();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002238
2239 if (size <= 0)
2240 {
2241 return false;
2242 }
2243
2244 bool mipmapping;
2245
2246 switch (mMinFilter)
2247 {
2248 case GL_NEAREST:
2249 case GL_LINEAR:
2250 mipmapping = false;
2251 break;
2252 case GL_NEAREST_MIPMAP_NEAREST:
2253 case GL_LINEAR_MIPMAP_NEAREST:
2254 case GL_NEAREST_MIPMAP_LINEAR:
2255 case GL_LINEAR_MIPMAP_LINEAR:
2256 mipmapping = true;
2257 break;
2258 default: UNREACHABLE();
2259 }
2260
2261 for (int face = 0; face < 6; face++)
2262 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002263 if (mImageArray[face][0].getWidth() != size || mImageArray[face][0].getHeight() != size)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002264 {
2265 return false;
2266 }
2267 }
2268
daniel@transgaming.combbeffbb2011-11-09 17:46:11 +00002269 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) ||
2270 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsFloat16LinearFilter()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002271 {
2272 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
2273 {
2274 return false;
2275 }
2276 }
2277
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002278 bool npot = getContext()->supportsNonPower2Texture();
2279
2280 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002281 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002282 if ((getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE) && !isPow2(size))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002283 {
2284 return false;
2285 }
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002286 }
2287
2288 if (mipmapping)
2289 {
2290 if (!npot)
2291 {
2292 if (!isPow2(size))
2293 {
2294 return false;
2295 }
2296 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002297
2298 int q = log2(size);
2299
2300 for (int face = 0; face < 6; face++)
2301 {
2302 for (int level = 1; level <= q; level++)
2303 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002304 if (mImageArray[face][level].getFormat() != mImageArray[0][0].getFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002305 {
2306 return false;
2307 }
2308
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002309 if (mImageArray[face][level].getType() != mImageArray[0][0].getType())
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002310 {
2311 return false;
2312 }
2313
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002314 if (mImageArray[face][level].getWidth() != std::max(1, size >> level))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002315 {
2316 return false;
2317 }
2318
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002319 ASSERT(mImageArray[face][level].getHeight() == mImageArray[face][level].getWidth());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002320 }
2321 }
2322 }
2323
2324 return true;
2325}
2326
2327bool TextureCubeMap::isCompressed() const
2328{
2329 return IsCompressed(getInternalFormat());
2330}
2331
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002332IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
2333{
2334 return mTexture;
2335}
2336
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002337// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002338void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002339{
2340 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002341 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002342 GLint levels = creationLevels(mImageArray[0][0].getWidth(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002343
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002344 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002345 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].getWidth(), levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002346
2347 if (FAILED(result))
2348 {
2349 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002350 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002351 }
2352
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002353 if (mTexture)
2354 {
2355 mTexture->Release();
2356 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002357
2358 mTexture = texture;
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00002359 mSerial = issueSerial();
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00002360 for(int face = 0; face < 6; face++) mFaceProxies[face].set(NULL);
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002361 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002362 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002363}
2364
2365void TextureCubeMap::updateTexture()
2366{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002367 for (int face = 0; face < 6; face++)
2368 {
2369 int levels = levelCount();
2370 for (int level = 0; level < levels; level++)
2371 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002372 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002373
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00002374 if (image->isDirty())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002375 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002376 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002377 }
2378 }
2379 }
2380}
2381
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002382void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002383{
2384 IDirect3DCubeTexture9 *texture = NULL;
2385
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002386 if (mImageArray[0][0].getWidth() != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002387 {
2388 egl::Display *display = getDisplay();
2389 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002390 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002391 GLint levels = creationLevels(mImageArray[0][0].getWidth(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002392
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002393 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].getWidth(), levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002394
2395 if (FAILED(result))
2396 {
2397 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002398 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002399 }
2400
2401 if (mTexture != NULL)
2402 {
2403 int levels = levelCount();
2404 for (int f = 0; f < 6; f++)
2405 {
2406 for (int i = 0; i < levels; i++)
2407 {
2408 IDirect3DSurface9 *source;
2409 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2410
2411 if (FAILED(result))
2412 {
2413 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2414
2415 texture->Release();
2416
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002417 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002418 }
2419
2420 IDirect3DSurface9 *dest;
2421 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2422
2423 if (FAILED(result))
2424 {
2425 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2426
2427 texture->Release();
2428 source->Release();
2429
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002430 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002431 }
2432
2433 display->endScene();
2434 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2435
2436 if (FAILED(result))
2437 {
2438 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2439
2440 texture->Release();
2441 source->Release();
2442 dest->Release();
2443
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002444 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002445 }
daniel@transgaming.coma1a86202011-08-09 13:41:08 +00002446
2447 source->Release();
2448 dest->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002449 }
2450 }
2451 }
2452 }
2453
2454 if (mTexture != NULL)
2455 {
2456 mTexture->Release();
2457 }
2458
2459 mTexture = texture;
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00002460 mSerial = issueSerial();
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00002461 for(int face = 0; face < 6; face++) mFaceProxies[face].set(NULL);
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002462 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002463 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002464}
2465
daniel@transgaming.com61208202011-03-21 16:38:50 +00002466void 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 +00002467{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002468 redefineImage(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002469
daniel@transgaming.com61208202011-03-21 16:38:50 +00002470 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002471}
2472
2473unsigned int TextureCubeMap::faceIndex(GLenum face)
2474{
2475 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2476 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2477 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2478 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2479 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2480
2481 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2482}
2483
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002484void TextureCubeMap::redefineImage(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002485{
daniel@transgaming.com41634052011-11-09 17:46:24 +00002486 bool redefined = mImageArray[face][level].redefine(format, width, height, type);
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002487
daniel@transgaming.com41634052011-11-09 17:46:24 +00002488 if (mTexture && redefined)
daniel@transgaming.com61208202011-03-21 16:38:50 +00002489 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002490 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2491 {
2492 for (int f = 0; f < 6; f++)
2493 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002494 mImageArray[f][i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002495 }
2496 }
2497
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002498 mTexture->Release();
2499 mTexture = NULL;
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00002500 mSerial = 0;
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00002501 for(int face = 0; face < 6; face++) mFaceProxies[face].set(NULL);
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002502 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002503 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002504}
2505
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002506void 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 +00002507{
2508 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2509
2510 if (!renderTarget)
2511 {
2512 ERR("Failed to retrieve the render target.");
2513 return error(GL_OUT_OF_MEMORY);
2514 }
2515
2516 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002517 redefineImage(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002518
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002519 if (!mImageArray[faceindex][level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002520 {
daniel@transgaming.com90cfcc92011-11-09 17:45:48 +00002521 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
2522 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002523 }
2524 else
2525 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002526 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002527 {
2528 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002529 }
daniel@transgaming.com3b3c1d42011-06-08 20:38:09 +00002530
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002531 mImageArray[faceindex][level].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002532
2533 ASSERT(width == height);
2534
2535 if (width > 0 && level < levelCount())
2536 {
2537 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2538 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2539 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2540 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2541 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2542
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002543 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[faceindex][level].getWidth());
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002544
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002545 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2546
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002547 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002548 dest->Release();
2549 }
2550 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002551}
2552
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002553IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum target, unsigned int level)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002554{
2555 if (mTexture == NULL)
2556 {
2557 UNREACHABLE();
2558 return NULL;
2559 }
2560
2561 IDirect3DSurface9 *surface = NULL;
2562
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002563 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), level, &surface);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002564
2565 return (SUCCEEDED(hr)) ? surface : NULL;
2566}
2567
2568void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2569{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002570 GLsizei size = mImageArray[faceIndex(target)][level].getWidth();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002571
2572 if (xoffset + width > size || yoffset + height > size)
2573 {
2574 return error(GL_INVALID_VALUE);
2575 }
2576
2577 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2578
2579 if (!renderTarget)
2580 {
2581 ERR("Failed to retrieve the render target.");
2582 return error(GL_OUT_OF_MEMORY);
2583 }
2584
2585 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com01dae852011-11-09 17:44:53 +00002586
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002587 if (!mImageArray[faceindex][level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002588 {
daniel@transgaming.com90cfcc92011-11-09 17:45:48 +00002589 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
2590 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002591 }
2592 else
2593 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002594 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002595 {
2596 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002597 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002598
2599 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002600
2601 if (level < levelCount())
2602 {
2603 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2604 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2605 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2606 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2607 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2608
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002609 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].getWidth());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002610
2611 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2612
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002613 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0][0].getFormat(), xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002614 dest->Release();
2615 }
2616 }
2617}
2618
2619bool TextureCubeMap::isCubeComplete() const
2620{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002621 if (mImageArray[0][0].getWidth() == 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002622 {
2623 return false;
2624 }
2625
2626 for (unsigned int f = 1; f < 6; f++)
2627 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002628 if (mImageArray[f][0].getWidth() != mImageArray[0][0].getWidth()
2629 || mImageArray[f][0].getFormat() != mImageArray[0][0].getFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002630 {
2631 return false;
2632 }
2633 }
2634
2635 return true;
2636}
2637
2638void TextureCubeMap::generateMipmaps()
2639{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002640 if (!isCubeComplete())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002641 {
2642 return error(GL_INVALID_OPERATION);
2643 }
2644
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002645 if (!getContext()->supportsNonPower2Texture())
2646 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002647 if (!isPow2(mImageArray[0][0].getWidth()))
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002648 {
2649 return error(GL_INVALID_OPERATION);
2650 }
2651 }
2652
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002653 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002654 unsigned int q = log2(mImageArray[0][0].getWidth());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002655 for (unsigned int f = 0; f < 6; f++)
2656 {
2657 for (unsigned int i = 1; i <= q; i++)
2658 {
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00002659 redefineImage(f, i, mImageArray[f][0].getFormat(),
2660 std::max(mImageArray[f][0].getWidth() >> i, 1),
2661 std::max(mImageArray[f][0].getWidth() >> i, 1),
2662 mImageArray[f][0].getType());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002663 }
2664 }
2665
daniel@transgaming.com9d4eac72011-11-09 17:45:53 +00002666 if (mTexture && mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002667 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002668 for (unsigned int f = 0; f < 6; f++)
2669 {
2670 for (unsigned int i = 1; i <= q; i++)
2671 {
2672 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2673 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2674
2675 if (upper != NULL && lower != NULL)
2676 {
2677 getBlitter()->boxFilter(upper, lower);
2678 }
2679
2680 if (upper != NULL) upper->Release();
2681 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002682
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002683 mImageArray[f][i].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002684 }
2685 }
2686 }
2687 else
2688 {
2689 for (unsigned int f = 0; f < 6; f++)
2690 {
2691 for (unsigned int i = 1; i <= q; i++)
2692 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002693 if (mImageArray[f][i].getSurface() == NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002694 {
2695 return error(GL_OUT_OF_MEMORY);
2696 }
2697
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002698 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 +00002699 {
2700 ERR(" failed to load filter %d to %d.", i - 1, i);
2701 }
2702
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002703 mImageArray[f][i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002704 }
2705 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002706 }
2707}
2708
2709Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2710{
2711 if (!IsCubemapTextureTarget(target))
2712 {
2713 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2714 }
2715
2716 unsigned int face = faceIndex(target);
2717
2718 if (mFaceProxies[face].get() == NULL)
2719 {
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00002720 mFaceProxies[face].set(new Renderbuffer(id(), new RenderbufferTexture(this, target)));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002721 }
2722
2723 return mFaceProxies[face].get();
2724}
2725
2726IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2727{
2728 ASSERT(IsCubemapTextureTarget(target));
2729
daniel@transgaming.com9d4eac72011-11-09 17:45:53 +00002730 if (!mTexture || !mIsRenderable)
daniel@transgaming.com61208202011-03-21 16:38:50 +00002731 {
2732 convertToRenderTarget();
2733 }
2734
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002735 if (mTexture == NULL)
2736 {
2737 return NULL;
2738 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002739
2740 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002741
2742 IDirect3DSurface9 *renderTarget = NULL;
2743 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2744
2745 return renderTarget;
2746}
2747
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002748}