blob: 4f91555b881eba3458d91121365bb882573bf6fc [file] [log] [blame]
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Texture.cpp: Implements the gl::Texture class and its derived classes
8// Texture2D and TextureCubeMap. Implements GL texture objects and related
9// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
10
11#include "libGLESv2/Texture.h"
12
13#include <d3dx9tex.h>
14
15#include <algorithm>
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +000016#include <intrin.h>
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000017
18#include "common/debug.h"
19
jbauman@chromium.orgae345802011-03-30 22:04:25 +000020#include "libEGL/Display.h"
21
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000022#include "libGLESv2/main.h"
23#include "libGLESv2/mathutil.h"
24#include "libGLESv2/utilities.h"
25#include "libGLESv2/Blit.h"
26#include "libGLESv2/Framebuffer.h"
27
28namespace gl
29{
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +000030unsigned int Texture::mCurrentSerial = 1;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000031
daniel@transgaming.comde631782011-11-09 17:45:04 +000032Image::Image()
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000033 : mWidth(0), mHeight(0), mDirty(false), mSurface(NULL), mFormat(GL_NONE), mType(GL_UNSIGNED_BYTE)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000034{
35}
36
daniel@transgaming.comde631782011-11-09 17:45:04 +000037Image::~Image()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000038{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000039 if (mSurface)
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +000040 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000041 mSurface->Release();
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +000042 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000043}
44
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000045void Image::redefine(GLenum format, GLsizei width, GLsizei height, GLenum type)
46{
daniel@transgaming.com4c0a7712011-11-09 17:45:19 +000047 if (mWidth != width ||
48 mHeight != height ||
49 mFormat != format ||
50 mType != type)
51 {
52 if (mSurface)
53 {
54 mSurface->Release();
55 mSurface = NULL;
56 }
57 }
58
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000059 mWidth = width;
60 mHeight = height;
61 mFormat = format;
62 mType = type;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000063}
64
65void Image::createSurface()
66{
67 if(mSurface)
68 {
69 return;
70 }
71
72 IDirect3DTexture9 *newTexture = NULL;
73 IDirect3DSurface9 *newSurface = NULL;
74
75 if (mWidth != 0 && mHeight != 0)
76 {
77 int levelToFetch = 0;
78 GLsizei requestWidth = mWidth;
79 GLsizei requestHeight = mHeight;
80 if (IsCompressed(mFormat) && (mWidth % 4 != 0 || mHeight % 4 != 0))
81 {
82 bool isMult4 = false;
83 int upsampleCount = 0;
84 while (!isMult4)
85 {
86 requestWidth <<= 1;
87 requestHeight <<= 1;
88 upsampleCount++;
89 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
90 {
91 isMult4 = true;
92 }
93 }
94 levelToFetch = upsampleCount;
95 }
96
97 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, getD3DFormat(),
98 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
99
100 if (FAILED(result))
101 {
102 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com73de05a2011-11-09 17:45:24 +0000103 ERR("Creating image surface failed.");
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000104 return error(GL_OUT_OF_MEMORY);
105 }
106
107 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
108 newTexture->Release();
109 }
110
111 mSurface = newSurface;
daniel@transgaming.com839fb9b2011-11-09 17:45:43 +0000112 mDirty = false;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000113}
114
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +0000115HRESULT Image::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect)
116{
117 createSurface();
118
119 HRESULT result = D3DERR_INVALIDCALL;
120
121 if (mSurface)
122 {
123 result = mSurface->LockRect(lockedRect, rect, 0);
124 ASSERT(SUCCEEDED(result));
125
126 mDirty = true;
127 }
128
129 return result;
130}
131
132void Image::unlock()
133{
134 if (mSurface)
135 {
136 HRESULT result = mSurface->UnlockRect();
137 ASSERT(SUCCEEDED(result));
138 }
139}
140
daniel@transgaming.comde631782011-11-09 17:45:04 +0000141bool Image::isRenderable() const
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000142{
143 switch(getD3DFormat())
144 {
145 case D3DFMT_L8:
146 case D3DFMT_A8L8:
147 case D3DFMT_DXT1:
gman@chromium.org50c526d2011-08-10 05:19:44 +0000148 case D3DFMT_DXT3:
149 case D3DFMT_DXT5:
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000150 return false;
151 case D3DFMT_A8R8G8B8:
152 case D3DFMT_X8R8G8B8:
153 case D3DFMT_A16B16G16R16F:
154 case D3DFMT_A32B32G32R32F:
155 return true;
156 default:
157 UNREACHABLE();
158 }
159
160 return false;
161}
162
daniel@transgaming.comde631782011-11-09 17:45:04 +0000163D3DFORMAT Image::getD3DFormat() const
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000164{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000165 if (mFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
166 mFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000167 {
168 return D3DFMT_DXT1;
169 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000170 else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE)
gman@chromium.org50c526d2011-08-10 05:19:44 +0000171 {
172 return D3DFMT_DXT3;
173 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000174 else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE)
gman@chromium.org50c526d2011-08-10 05:19:44 +0000175 {
176 return D3DFMT_DXT5;
177 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000178 else if (mType == GL_FLOAT)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000179 {
180 return D3DFMT_A32B32G32R32F;
181 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000182 else if (mType == GL_HALF_FLOAT_OES)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000183 {
184 return D3DFMT_A16B16G16R16F;
185 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000186 else if (mType == GL_UNSIGNED_BYTE)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000187 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000188 if (mFormat == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000189 {
190 return D3DFMT_L8;
191 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000192 else if (mFormat == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000193 {
194 return D3DFMT_A8L8;
195 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000196 else if (mFormat == GL_RGB)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000197 {
198 return D3DFMT_X8R8G8B8;
199 }
200
201 return D3DFMT_A8R8G8B8;
202 }
203
204 return D3DFMT_A8R8G8B8;
205}
206
daniel@transgaming.com73de05a2011-11-09 17:45:24 +0000207IDirect3DSurface9 *Image::getSurface()
208{
209 createSurface();
210
211 return mSurface;
212}
213
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000214// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
215// into the target pixel rectangle at output with outputPitch bytes in between each line.
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000216void Image::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum type,
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000217 GLint unpackAlignment, const void *input, size_t outputPitch, void *output) const
218{
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000219 GLsizei inputPitch = -ComputePitch(width, mFormat, type, unpackAlignment);
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000220 input = ((char*)input) - inputPitch * (height - 1);
221
222 switch (type)
223 {
224 case GL_UNSIGNED_BYTE:
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000225 switch (mFormat)
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000226 {
227 case GL_ALPHA:
228 loadAlphaData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
229 break;
230 case GL_LUMINANCE:
231 loadLuminanceData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, getD3DFormat() == D3DFMT_L8);
232 break;
233 case GL_LUMINANCE_ALPHA:
234 loadLuminanceAlphaData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, getD3DFormat() == D3DFMT_A8L8);
235 break;
236 case GL_RGB:
237 loadRGBUByteData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
238 break;
239 case GL_RGBA:
240 if (supportsSSE2())
241 {
242 loadRGBAUByteDataSSE2(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
243 }
244 else
245 {
246 loadRGBAUByteData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
247 }
248 break;
249 case GL_BGRA_EXT:
250 loadBGRAData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
251 break;
252 default: UNREACHABLE();
253 }
254 break;
255 case GL_UNSIGNED_SHORT_5_6_5:
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000256 switch (mFormat)
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000257 {
258 case GL_RGB:
259 loadRGB565Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
260 break;
261 default: UNREACHABLE();
262 }
263 break;
264 case GL_UNSIGNED_SHORT_4_4_4_4:
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000265 switch (mFormat)
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000266 {
267 case GL_RGBA:
268 loadRGBA4444Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
269 break;
270 default: UNREACHABLE();
271 }
272 break;
273 case GL_UNSIGNED_SHORT_5_5_5_1:
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000274 switch (mFormat)
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000275 {
276 case GL_RGBA:
277 loadRGBA5551Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
278 break;
279 default: UNREACHABLE();
280 }
281 break;
282 case GL_FLOAT:
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000283 switch (mFormat)
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000284 {
285 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
286 case GL_ALPHA:
287 loadAlphaFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
288 break;
289 case GL_LUMINANCE:
290 loadLuminanceFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
291 break;
292 case GL_LUMINANCE_ALPHA:
293 loadLuminanceAlphaFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
294 break;
295 case GL_RGB:
296 loadRGBFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
297 break;
298 case GL_RGBA:
299 loadRGBAFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
300 break;
301 default: UNREACHABLE();
302 }
303 break;
304 case GL_HALF_FLOAT_OES:
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000305 switch (mFormat)
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000306 {
307 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
308 case GL_ALPHA:
309 loadAlphaHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
310 break;
311 case GL_LUMINANCE:
312 loadLuminanceHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
313 break;
314 case GL_LUMINANCE_ALPHA:
315 loadLuminanceAlphaHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
316 break;
317 case GL_RGB:
318 loadRGBHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
319 break;
320 case GL_RGBA:
321 loadRGBAHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
322 break;
323 default: UNREACHABLE();
324 }
325 break;
326 default: UNREACHABLE();
327 }
328}
329
330void Image::loadAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
331 int inputPitch, const void *input, size_t outputPitch, void *output) const
332{
333 const unsigned char *source = NULL;
334 unsigned char *dest = NULL;
335
336 for (int y = 0; y < height; y++)
337 {
338 source = static_cast<const unsigned char*>(input) + y * inputPitch;
339 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
340 for (int x = 0; x < width; x++)
341 {
342 dest[4 * x + 0] = 0;
343 dest[4 * x + 1] = 0;
344 dest[4 * x + 2] = 0;
345 dest[4 * x + 3] = source[x];
346 }
347 }
348}
349
350void Image::loadAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
351 int inputPitch, const void *input, size_t outputPitch, void *output) const
352{
353 const float *source = NULL;
354 float *dest = NULL;
355
356 for (int y = 0; y < height; y++)
357 {
358 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
359 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
360 for (int x = 0; x < width; x++)
361 {
362 dest[4 * x + 0] = 0;
363 dest[4 * x + 1] = 0;
364 dest[4 * x + 2] = 0;
365 dest[4 * x + 3] = source[x];
366 }
367 }
368}
369
370void Image::loadAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
371 int inputPitch, const void *input, size_t outputPitch, void *output) const
372{
373 const unsigned short *source = NULL;
374 unsigned short *dest = NULL;
375
376 for (int y = 0; y < height; y++)
377 {
378 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
379 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
380 for (int x = 0; x < width; x++)
381 {
382 dest[4 * x + 0] = 0;
383 dest[4 * x + 1] = 0;
384 dest[4 * x + 2] = 0;
385 dest[4 * x + 3] = source[x];
386 }
387 }
388}
389
390void Image::loadLuminanceData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
391 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
392{
393 const int destBytesPerPixel = native? 1: 4;
394 const unsigned char *source = NULL;
395 unsigned char *dest = NULL;
396
397 for (int y = 0; y < height; y++)
398 {
399 source = static_cast<const unsigned char*>(input) + y * inputPitch;
400 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
401
402 if (!native) // BGRA8 destination format
403 {
404 for (int x = 0; x < width; x++)
405 {
406 dest[4 * x + 0] = source[x];
407 dest[4 * x + 1] = source[x];
408 dest[4 * x + 2] = source[x];
409 dest[4 * x + 3] = 0xFF;
410 }
411 }
412 else // L8 destination format
413 {
414 memcpy(dest, source, width);
415 }
416 }
417}
418
419void Image::loadLuminanceFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
420 int inputPitch, const void *input, size_t outputPitch, void *output) const
421{
422 const float *source = NULL;
423 float *dest = NULL;
424
425 for (int y = 0; y < height; y++)
426 {
427 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
428 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
429 for (int x = 0; x < width; x++)
430 {
431 dest[4 * x + 0] = source[x];
432 dest[4 * x + 1] = source[x];
433 dest[4 * x + 2] = source[x];
434 dest[4 * x + 3] = 1.0f;
435 }
436 }
437}
438
439void Image::loadLuminanceHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
440 int inputPitch, const void *input, size_t outputPitch, void *output) const
441{
442 const unsigned short *source = NULL;
443 unsigned short *dest = NULL;
444
445 for (int y = 0; y < height; y++)
446 {
447 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
448 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
449 for (int x = 0; x < width; x++)
450 {
451 dest[4 * x + 0] = source[x];
452 dest[4 * x + 1] = source[x];
453 dest[4 * x + 2] = source[x];
454 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
455 }
456 }
457}
458
459void Image::loadLuminanceAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
460 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
461{
462 const int destBytesPerPixel = native? 2: 4;
463 const unsigned char *source = NULL;
464 unsigned char *dest = NULL;
465
466 for (int y = 0; y < height; y++)
467 {
468 source = static_cast<const unsigned char*>(input) + y * inputPitch;
469 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
470
471 if (!native) // BGRA8 destination format
472 {
473 for (int x = 0; x < width; x++)
474 {
475 dest[4 * x + 0] = source[2*x+0];
476 dest[4 * x + 1] = source[2*x+0];
477 dest[4 * x + 2] = source[2*x+0];
478 dest[4 * x + 3] = source[2*x+1];
479 }
480 }
481 else
482 {
483 memcpy(dest, source, width * 2);
484 }
485 }
486}
487
488void Image::loadLuminanceAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
489 int inputPitch, const void *input, size_t outputPitch, void *output) const
490{
491 const float *source = NULL;
492 float *dest = NULL;
493
494 for (int y = 0; y < height; y++)
495 {
496 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
497 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
498 for (int x = 0; x < width; x++)
499 {
500 dest[4 * x + 0] = source[2*x+0];
501 dest[4 * x + 1] = source[2*x+0];
502 dest[4 * x + 2] = source[2*x+0];
503 dest[4 * x + 3] = source[2*x+1];
504 }
505 }
506}
507
508void Image::loadLuminanceAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
509 int inputPitch, const void *input, size_t outputPitch, void *output) const
510{
511 const unsigned short *source = NULL;
512 unsigned short *dest = NULL;
513
514 for (int y = 0; y < height; y++)
515 {
516 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
517 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
518 for (int x = 0; x < width; x++)
519 {
520 dest[4 * x + 0] = source[2*x+0];
521 dest[4 * x + 1] = source[2*x+0];
522 dest[4 * x + 2] = source[2*x+0];
523 dest[4 * x + 3] = source[2*x+1];
524 }
525 }
526}
527
528void Image::loadRGBUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
529 int inputPitch, const void *input, size_t outputPitch, void *output) const
530{
531 const unsigned char *source = NULL;
532 unsigned char *dest = NULL;
533
534 for (int y = 0; y < height; y++)
535 {
536 source = static_cast<const unsigned char*>(input) + y * inputPitch;
537 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
538 for (int x = 0; x < width; x++)
539 {
540 dest[4 * x + 0] = source[x * 3 + 2];
541 dest[4 * x + 1] = source[x * 3 + 1];
542 dest[4 * x + 2] = source[x * 3 + 0];
543 dest[4 * x + 3] = 0xFF;
544 }
545 }
546}
547
548void Image::loadRGB565Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
549 int inputPitch, const void *input, size_t outputPitch, void *output) const
550{
551 const unsigned short *source = NULL;
552 unsigned char *dest = NULL;
553
554 for (int y = 0; y < height; y++)
555 {
556 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
557 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
558 for (int x = 0; x < width; x++)
559 {
560 unsigned short rgba = source[x];
561 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
562 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
563 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
564 dest[4 * x + 3] = 0xFF;
565 }
566 }
567}
568
569void Image::loadRGBFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
570 int inputPitch, const void *input, size_t outputPitch, void *output) const
571{
572 const float *source = NULL;
573 float *dest = NULL;
574
575 for (int y = 0; y < height; y++)
576 {
577 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
578 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
579 for (int x = 0; x < width; x++)
580 {
581 dest[4 * x + 0] = source[x * 3 + 0];
582 dest[4 * x + 1] = source[x * 3 + 1];
583 dest[4 * x + 2] = source[x * 3 + 2];
584 dest[4 * x + 3] = 1.0f;
585 }
586 }
587}
588
589void Image::loadRGBHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
590 int inputPitch, const void *input, size_t outputPitch, void *output) const
591{
592 const unsigned short *source = NULL;
593 unsigned short *dest = NULL;
594
595 for (int y = 0; y < height; y++)
596 {
597 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
598 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
599 for (int x = 0; x < width; x++)
600 {
601 dest[4 * x + 0] = source[x * 3 + 0];
602 dest[4 * x + 1] = source[x * 3 + 1];
603 dest[4 * x + 2] = source[x * 3 + 2];
604 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
605 }
606 }
607}
608
609void Image::loadRGBAUByteDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
610 int inputPitch, const void *input, size_t outputPitch, void *output) const
611{
612 const unsigned int *source = NULL;
613 unsigned int *dest = NULL;
614 __m128i brMask = _mm_set1_epi32(0x00ff00ff);
615
616 for (int y = 0; y < height; y++)
617 {
618 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
619 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
620 int x = 0;
621
622 // Make output writes aligned
623 for (x = 0; ((reinterpret_cast<intptr_t>(&dest[x]) & 15) != 0) && x < width; x++)
624 {
625 unsigned int rgba = source[x];
626 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
627 }
628
629 for (; x + 3 < width; x += 4)
630 {
631 __m128i sourceData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&source[x]));
632 // Mask out g and a, which don't change
633 __m128i gaComponents = _mm_andnot_si128(brMask, sourceData);
634 // Mask out b and r
635 __m128i brComponents = _mm_and_si128(sourceData, brMask);
636 // Swap b and r
637 __m128i brSwapped = _mm_shufflehi_epi16(_mm_shufflelo_epi16(brComponents, _MM_SHUFFLE(2, 3, 0, 1)), _MM_SHUFFLE(2, 3, 0, 1));
638 __m128i result = _mm_or_si128(gaComponents, brSwapped);
639 _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), result);
640 }
641
642 // Perform leftover writes
643 for (; x < width; x++)
644 {
645 unsigned int rgba = source[x];
646 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
647 }
648 }
649}
650
651void Image::loadRGBAUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
652 int inputPitch, const void *input, size_t outputPitch, void *output) const
653{
654 const unsigned int *source = NULL;
655 unsigned int *dest = NULL;
656 for (int y = 0; y < height; y++)
657 {
658 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
659 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
660
661 for (int x = 0; x < width; x++)
662 {
663 unsigned int rgba = source[x];
664 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
665 }
666 }
667}
668
669void Image::loadRGBA4444Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
670 int inputPitch, const void *input, size_t outputPitch, void *output) const
671{
672 const unsigned short *source = NULL;
673 unsigned char *dest = NULL;
674
675 for (int y = 0; y < height; y++)
676 {
677 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
678 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
679 for (int x = 0; x < width; x++)
680 {
681 unsigned short rgba = source[x];
682 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
683 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
684 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
685 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
686 }
687 }
688}
689
690void Image::loadRGBA5551Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
691 int inputPitch, const void *input, size_t outputPitch, void *output) const
692{
693 const unsigned short *source = NULL;
694 unsigned char *dest = NULL;
695
696 for (int y = 0; y < height; y++)
697 {
698 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
699 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
700 for (int x = 0; x < width; x++)
701 {
702 unsigned short rgba = source[x];
703 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
704 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
705 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
706 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
707 }
708 }
709}
710
711void Image::loadRGBAFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
712 int inputPitch, const void *input, size_t outputPitch, void *output) const
713{
714 const float *source = NULL;
715 float *dest = NULL;
716
717 for (int y = 0; y < height; y++)
718 {
719 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
720 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
721 memcpy(dest, source, width * 16);
722 }
723}
724
725void Image::loadRGBAHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
726 int inputPitch, const void *input, size_t outputPitch, void *output) const
727{
728 const unsigned char *source = NULL;
729 unsigned char *dest = NULL;
730
731 for (int y = 0; y < height; y++)
732 {
733 source = static_cast<const unsigned char*>(input) + y * inputPitch;
734 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
735 memcpy(dest, source, width * 8);
736 }
737}
738
739void Image::loadBGRAData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
740 int inputPitch, const void *input, size_t outputPitch, void *output) const
741{
742 const unsigned char *source = NULL;
743 unsigned char *dest = NULL;
744
745 for (int y = 0; y < height; y++)
746 {
747 source = static_cast<const unsigned char*>(input) + y * inputPitch;
748 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
749 memcpy(dest, source, width*4);
750 }
751}
752
753void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
754 int inputPitch, const void *input, size_t outputPitch, void *output) const {
755 switch (getD3DFormat())
756 {
757 case D3DFMT_DXT1:
758 loadDXT1Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
759 break;
760 case D3DFMT_DXT3:
761 loadDXT3Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
762 break;
763 case D3DFMT_DXT5:
764 loadDXT5Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
765 break;
766 }
767}
768
769static void FlipCopyDXT1BlockFull(const unsigned int* source, unsigned int* dest) {
770 // A DXT1 block layout is:
771 // [0-1] color0.
772 // [2-3] color1.
773 // [4-7] color bitmap, 2 bits per pixel.
774 // So each of the 4-7 bytes represents one line, flipping a block is just
775 // flipping those bytes.
776
777 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
778 dest[0] = source[0];
779
780 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
781 dest[1] = (source[1] >> 24) |
782 ((source[1] << 8) & 0x00FF0000) |
783 ((source[1] >> 8) & 0x0000FF00) |
784 (source[1] << 24);
785}
786
787// Flips the first 2 lines of a DXT1 block in the y direction.
788static void FlipCopyDXT1BlockHalf(const unsigned int* source, unsigned int* dest) {
789 // See layout above.
790 dest[0] = source[0];
791 dest[1] = ((source[1] << 8) & 0x0000FF00) |
792 ((source[1] >> 8) & 0x000000FF);
793}
794
795// Flips a full DXT3 block in the y direction.
796static void FlipCopyDXT3BlockFull(const unsigned int* source, unsigned int* dest) {
797 // A DXT3 block layout is:
798 // [0-7] alpha bitmap, 4 bits per pixel.
799 // [8-15] a DXT1 block.
800
801 // First and Second 32 bits are 4bit per pixel alpha and need to be flipped.
802 dest[0] = (source[1] >> 16) | (source[1] << 16);
803 dest[1] = (source[0] >> 16) | (source[0] << 16);
804
805 // And flip the DXT1 block using the above function.
806 FlipCopyDXT1BlockFull(source + 2, dest + 2);
807}
808
809// Flips the first 2 lines of a DXT3 block in the y direction.
810static void FlipCopyDXT3BlockHalf(const unsigned int* source, unsigned int* dest) {
811 // See layout above.
812 dest[0] = (source[1] >> 16) | (source[1] << 16);
813 FlipCopyDXT1BlockHalf(source + 2, dest + 2);
814}
815
816// Flips a full DXT5 block in the y direction.
817static void FlipCopyDXT5BlockFull(const unsigned int* source, unsigned int* dest) {
818 // A DXT5 block layout is:
819 // [0] alpha0.
820 // [1] alpha1.
821 // [2-7] alpha bitmap, 3 bits per pixel.
822 // [8-15] a DXT1 block.
823
824 // The alpha bitmap doesn't easily map lines to bytes, so we have to
825 // interpret it correctly. Extracted from
826 // http://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt :
827 //
828 // The 6 "bits" bytes of the block are decoded into one 48-bit integer:
829 //
830 // bits = bits_0 + 256 * (bits_1 + 256 * (bits_2 + 256 * (bits_3 +
831 // 256 * (bits_4 + 256 * bits_5))))
832 //
833 // bits is a 48-bit unsigned integer, from which a three-bit control code
834 // is extracted for a texel at location (x,y) in the block using:
835 //
836 // code(x,y) = bits[3*(4*y+x)+1..3*(4*y+x)+0]
837 //
838 // where bit 47 is the most significant and bit 0 is the least
839 // significant bit.
840 const unsigned char* sourceBytes = static_cast<const unsigned char*>(static_cast<const void*>(source));
841 unsigned char* destBytes = static_cast<unsigned char*>(static_cast<void*>(dest));
842 unsigned int line_0_1 = sourceBytes[2] + 256 * (sourceBytes[3] + 256 * sourceBytes[4]);
843 unsigned int line_2_3 = sourceBytes[5] + 256 * (sourceBytes[6] + 256 * sourceBytes[7]);
844 // swap lines 0 and 1 in line_0_1.
845 unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) |
846 ((line_0_1 & 0xfff000) >> 12);
847 // swap lines 2 and 3 in line_2_3.
848 unsigned int line_3_2 = ((line_2_3 & 0x000fff) << 12) |
849 ((line_2_3 & 0xfff000) >> 12);
850 destBytes[0] = sourceBytes[0];
851 destBytes[1] = sourceBytes[1];
852 destBytes[2] = line_3_2 & 0xff;
853 destBytes[3] = (line_3_2 & 0xff00) >> 8;
854 destBytes[4] = (line_3_2 & 0xff0000) >> 16;
855 destBytes[5] = line_1_0 & 0xff;
856 destBytes[6] = (line_1_0 & 0xff00) >> 8;
857 destBytes[7] = (line_1_0 & 0xff0000) >> 16;
858
859 // And flip the DXT1 block using the above function.
860 FlipCopyDXT1BlockFull(source + 2, dest + 2);
861}
862
863// Flips the first 2 lines of a DXT5 block in the y direction.
864static void FlipCopyDXT5BlockHalf(const unsigned int* source, unsigned int* dest) {
865 // See layout above.
866 const unsigned char* sourceBytes = static_cast<const unsigned char*>(static_cast<const void*>(source));
867 unsigned char* destBytes = static_cast<unsigned char*>(static_cast<void*>(dest));
868 unsigned int line_0_1 = sourceBytes[2] + 256 * (sourceBytes[3] + 256 * sourceBytes[4]);
869 unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) |
870 ((line_0_1 & 0xfff000) >> 12);
871 destBytes[0] = sourceBytes[0];
872 destBytes[1] = sourceBytes[1];
873 destBytes[2] = line_1_0 & 0xff;
874 destBytes[3] = (line_1_0 & 0xff00) >> 8;
875 destBytes[4] = (line_1_0 & 0xff0000) >> 16;
876 FlipCopyDXT1BlockHalf(source + 2, dest + 2);
877}
878
879void Image::loadDXT1Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
880 int inputPitch, const void *input, size_t outputPitch, void *output) const
881{
882 ASSERT(xoffset % 4 == 0);
883 ASSERT(yoffset % 4 == 0);
884 ASSERT(width % 4 == 0 || width == 2 || width == 1);
885 ASSERT(inputPitch % 8 == 0);
886 ASSERT(outputPitch % 8 == 0);
887
888 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
889 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
890
891 // Round width up in case it is less than 4.
892 int blocksAcross = (width + 3) / 4;
893 int intsAcross = blocksAcross * 2;
894
895 switch (height)
896 {
897 case 1:
898 for (int x = 0; x < intsAcross; x += 2)
899 {
900 // just copy the block
901 dest[x] = source[x];
902 dest[x + 1] = source[x + 1];
903 }
904 break;
905 case 2:
906 for (int x = 0; x < intsAcross; x += 2)
907 {
908 FlipCopyDXT1BlockHalf(source + x, dest + x);
909 }
910 break;
911 default:
912 ASSERT(height % 4 == 0);
913 for (int y = 0; y < height / 4; ++y)
914 {
915 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
916 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
917
918 for (int x = 0; x < intsAcross; x += 2)
919 {
920 FlipCopyDXT1BlockFull(source + x, dest + x);
921 }
922 }
923 break;
924 }
925}
926
927void Image::loadDXT3Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
928 int inputPitch, const void *input, size_t outputPitch, void *output) const
929{
930 ASSERT(xoffset % 4 == 0);
931 ASSERT(yoffset % 4 == 0);
932 ASSERT(width % 4 == 0 || width == 2 || width == 1);
933 ASSERT(inputPitch % 16 == 0);
934 ASSERT(outputPitch % 16 == 0);
935
936 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
937 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
938
939 // Round width up in case it is less than 4.
940 int blocksAcross = (width + 3) / 4;
941 int intsAcross = blocksAcross * 4;
942
943 switch (height)
944 {
945 case 1:
946 for (int x = 0; x < intsAcross; x += 4)
947 {
948 // just copy the block
949 dest[x] = source[x];
950 dest[x + 1] = source[x + 1];
951 dest[x + 2] = source[x + 2];
952 dest[x + 3] = source[x + 3];
953 }
954 break;
955 case 2:
956 for (int x = 0; x < intsAcross; x += 4)
957 {
958 FlipCopyDXT3BlockHalf(source + x, dest + x);
959 }
960 break;
961 default:
962 ASSERT(height % 4 == 0);
963 for (int y = 0; y < height / 4; ++y)
964 {
965 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
966 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
967
968 for (int x = 0; x < intsAcross; x += 4)
969 {
970 FlipCopyDXT3BlockFull(source + x, dest + x);
971 }
972 }
973 break;
974 }
975}
976
977void Image::loadDXT5Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
978 int inputPitch, const void *input, size_t outputPitch, void *output) const
979{
980 ASSERT(xoffset % 4 == 0);
981 ASSERT(yoffset % 4 == 0);
982 ASSERT(width % 4 == 0 || width == 2 || width == 1);
983 ASSERT(inputPitch % 16 == 0);
984 ASSERT(outputPitch % 16 == 0);
985
986 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
987 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
988
989 // Round width up in case it is less than 4.
990 int blocksAcross = (width + 3) / 4;
991 int intsAcross = blocksAcross * 4;
992
993 switch (height)
994 {
995 case 1:
996 for (int x = 0; x < intsAcross; x += 4)
997 {
998 // just copy the block
999 dest[x] = source[x];
1000 dest[x + 1] = source[x + 1];
1001 dest[x + 2] = source[x + 2];
1002 dest[x + 3] = source[x + 3];
1003 }
1004 break;
1005 case 2:
1006 for (int x = 0; x < intsAcross; x += 4)
1007 {
1008 FlipCopyDXT5BlockHalf(source + x, dest + x);
1009 }
1010 break;
1011 default:
1012 ASSERT(height % 4 == 0);
1013 for (int y = 0; y < height / 4; ++y)
1014 {
1015 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
1016 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
1017
1018 for (int x = 0; x < intsAcross; x += 4)
1019 {
1020 FlipCopyDXT5BlockFull(source + x, dest + x);
1021 }
1022 }
1023 break;
1024 }
1025}
1026
daniel@transgaming.com90cfcc92011-11-09 17:45:48 +00001027// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
1028void Image::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
1029{
1030 IDirect3DDevice9 *device = getDevice();
1031 IDirect3DSurface9 *renderTargetData = NULL;
1032 D3DSURFACE_DESC description;
1033 renderTarget->GetDesc(&description);
1034
1035 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
1036
1037 if (FAILED(result))
1038 {
1039 ERR("Could not create matching destination surface.");
1040 return error(GL_OUT_OF_MEMORY);
1041 }
1042
1043 result = device->GetRenderTargetData(renderTarget, renderTargetData);
1044
1045 if (FAILED(result))
1046 {
1047 ERR("GetRenderTargetData unexpectedly failed.");
1048 renderTargetData->Release();
1049 return error(GL_OUT_OF_MEMORY);
1050 }
1051
1052 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
1053 int destYOffset = transformPixelYOffset(yoffset, height, mHeight);
1054 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
1055
1056 if (isRenderable())
1057 {
1058 result = D3DXLoadSurfaceFromSurface(getSurface(), NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0);
1059
1060 if (FAILED(result))
1061 {
1062 ERR("Copying surfaces unexpectedly failed.");
1063 renderTargetData->Release();
1064 return error(GL_OUT_OF_MEMORY);
1065 }
1066 }
1067 else
1068 {
1069 D3DLOCKED_RECT sourceLock = {0};
1070 result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
1071
1072 if (FAILED(result))
1073 {
1074 ERR("Failed to lock the source surface (rectangle might be invalid).");
1075 renderTargetData->Release();
1076 return error(GL_OUT_OF_MEMORY);
1077 }
1078
1079 D3DLOCKED_RECT destLock = {0};
1080 result = lock(&destLock, &destRect);
1081
1082 if (FAILED(result))
1083 {
1084 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1085 renderTargetData->UnlockRect();
1086 renderTargetData->Release();
1087 return error(GL_OUT_OF_MEMORY);
1088 }
1089
1090 if (destLock.pBits && sourceLock.pBits)
1091 {
1092 unsigned char *source = (unsigned char*)sourceLock.pBits;
1093 unsigned char *dest = (unsigned char*)destLock.pBits;
1094
1095 switch (description.Format)
1096 {
1097 case D3DFMT_X8R8G8B8:
1098 case D3DFMT_A8R8G8B8:
1099 switch(getD3DFormat())
1100 {
1101 case D3DFMT_L8:
1102 for(int y = 0; y < height; y++)
1103 {
1104 for(int x = 0; x < width; x++)
1105 {
1106 dest[x] = source[x * 4 + 2];
1107 }
1108
1109 source += sourceLock.Pitch;
1110 dest += destLock.Pitch;
1111 }
1112 break;
1113 case D3DFMT_A8L8:
1114 for(int y = 0; y < height; y++)
1115 {
1116 for(int x = 0; x < width; x++)
1117 {
1118 dest[x * 2 + 0] = source[x * 4 + 2];
1119 dest[x * 2 + 1] = source[x * 4 + 3];
1120 }
1121
1122 source += sourceLock.Pitch;
1123 dest += destLock.Pitch;
1124 }
1125 break;
1126 default:
1127 UNREACHABLE();
1128 }
1129 break;
1130 case D3DFMT_R5G6B5:
1131 switch(getD3DFormat())
1132 {
1133 case D3DFMT_L8:
1134 for(int y = 0; y < height; y++)
1135 {
1136 for(int x = 0; x < width; x++)
1137 {
1138 unsigned char red = source[x * 2 + 1] & 0xF8;
1139 dest[x] = red | (red >> 5);
1140 }
1141
1142 source += sourceLock.Pitch;
1143 dest += destLock.Pitch;
1144 }
1145 break;
1146 default:
1147 UNREACHABLE();
1148 }
1149 break;
1150 case D3DFMT_A1R5G5B5:
1151 switch(getD3DFormat())
1152 {
1153 case D3DFMT_L8:
1154 for(int y = 0; y < height; y++)
1155 {
1156 for(int x = 0; x < width; x++)
1157 {
1158 unsigned char red = source[x * 2 + 1] & 0x7C;
1159 dest[x] = (red << 1) | (red >> 4);
1160 }
1161
1162 source += sourceLock.Pitch;
1163 dest += destLock.Pitch;
1164 }
1165 break;
1166 case D3DFMT_A8L8:
1167 for(int y = 0; y < height; y++)
1168 {
1169 for(int x = 0; x < width; x++)
1170 {
1171 unsigned char red = source[x * 2 + 1] & 0x7C;
1172 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1173 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1174 }
1175
1176 source += sourceLock.Pitch;
1177 dest += destLock.Pitch;
1178 }
1179 break;
1180 default:
1181 UNREACHABLE();
1182 }
1183 break;
1184 default:
1185 UNREACHABLE();
1186 }
1187 }
1188
1189 unlock();
1190 renderTargetData->UnlockRect();
1191 }
1192
1193 renderTargetData->Release();
1194
1195 mDirty = true;
1196}
1197
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00001198Texture::Texture(GLuint id) : RefCountObject(id)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001199{
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00001200 mSerial = 0;
1201
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001202 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
1203 mMagFilter = GL_LINEAR;
1204 mWrapS = GL_REPEAT;
1205 mWrapT = GL_REPEAT;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001206 mDirtyParameters = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001207
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001208 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001209
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001210 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001211}
1212
1213Texture::~Texture()
1214{
1215}
1216
1217Blit *Texture::getBlitter()
1218{
1219 Context *context = getContext();
1220 return context->getBlitter();
1221}
1222
1223// Returns true on successful filter state update (valid enum parameter)
1224bool Texture::setMinFilter(GLenum filter)
1225{
1226 switch (filter)
1227 {
1228 case GL_NEAREST:
1229 case GL_LINEAR:
1230 case GL_NEAREST_MIPMAP_NEAREST:
1231 case GL_LINEAR_MIPMAP_NEAREST:
1232 case GL_NEAREST_MIPMAP_LINEAR:
1233 case GL_LINEAR_MIPMAP_LINEAR:
1234 {
1235 if (mMinFilter != filter)
1236 {
1237 mMinFilter = filter;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001238 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001239 }
1240 return true;
1241 }
1242 default:
1243 return false;
1244 }
1245}
1246
1247// Returns true on successful filter state update (valid enum parameter)
1248bool Texture::setMagFilter(GLenum filter)
1249{
1250 switch (filter)
1251 {
1252 case GL_NEAREST:
1253 case GL_LINEAR:
1254 {
1255 if (mMagFilter != filter)
1256 {
1257 mMagFilter = filter;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001258 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001259 }
1260 return true;
1261 }
1262 default:
1263 return false;
1264 }
1265}
1266
1267// Returns true on successful wrap state update (valid enum parameter)
1268bool Texture::setWrapS(GLenum wrap)
1269{
1270 switch (wrap)
1271 {
1272 case GL_REPEAT:
1273 case GL_CLAMP_TO_EDGE:
1274 case GL_MIRRORED_REPEAT:
1275 {
1276 if (mWrapS != wrap)
1277 {
1278 mWrapS = wrap;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001279 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001280 }
1281 return true;
1282 }
1283 default:
1284 return false;
1285 }
1286}
1287
1288// Returns true on successful wrap state update (valid enum parameter)
1289bool Texture::setWrapT(GLenum wrap)
1290{
1291 switch (wrap)
1292 {
1293 case GL_REPEAT:
1294 case GL_CLAMP_TO_EDGE:
1295 case GL_MIRRORED_REPEAT:
1296 {
1297 if (mWrapT != wrap)
1298 {
1299 mWrapT = wrap;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001300 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001301 }
1302 return true;
1303 }
1304 default:
1305 return false;
1306 }
1307}
1308
1309GLenum Texture::getMinFilter() const
1310{
1311 return mMinFilter;
1312}
1313
1314GLenum Texture::getMagFilter() const
1315{
1316 return mMagFilter;
1317}
1318
1319GLenum Texture::getWrapS() const
1320{
1321 return mWrapS;
1322}
1323
1324GLenum Texture::getWrapT() const
1325{
1326 return mWrapT;
1327}
1328
daniel@transgaming.com61208202011-03-21 16:38:50 +00001329void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001330{
daniel@transgaming.com73de05a2011-11-09 17:45:24 +00001331 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001332 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001333 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001334 HRESULT result = image->lock(&locked, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001335
1336 if (SUCCEEDED(result))
1337 {
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +00001338 image->loadData(0, 0, image->getWidth(), image->getHeight(), image->getType(), unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001339 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001340 }
1341
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001342 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001343 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001344}
1345
daniel@transgaming.com61208202011-03-21 16:38:50 +00001346void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001347{
daniel@transgaming.com73de05a2011-11-09 17:45:24 +00001348 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001349 {
1350 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001351 HRESULT result = image->lock(&locked, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001352
1353 if (SUCCEEDED(result))
1354 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001355 int inputPitch = ComputeCompressedPitch(image->getWidth(), image->getFormat());
1356 int inputSize = ComputeCompressedSize(image->getWidth(), image->getHeight(), image->getFormat());
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +00001357 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 +00001358 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001359 }
1360
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001361 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001362 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001363}
1364
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001365bool 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 +00001366{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001367 if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001368 {
1369 error(GL_INVALID_VALUE);
1370 return false;
1371 }
1372
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001373 if (IsCompressed(image->getFormat()))
jbauman@chromium.orge2f954c2011-05-03 20:45:27 +00001374 {
1375 error(GL_INVALID_OPERATION);
1376 return false;
1377 }
1378
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001379 if (format != image->getFormat())
jbauman@chromium.orge2f954c2011-05-03 20:45:27 +00001380 {
1381 error(GL_INVALID_OPERATION);
1382 return false;
1383 }
1384
daniel@transgaming.com73de05a2011-11-09 17:45:24 +00001385 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001386 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001387 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001388 HRESULT result = image->lock(&locked, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001389
1390 if (SUCCEEDED(result))
1391 {
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +00001392 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 +00001393 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001394 }
1395
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001396 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001397 }
1398
1399 return true;
1400}
1401
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001402bool 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 +00001403{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001404 if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001405 {
1406 error(GL_INVALID_VALUE);
1407 return false;
1408 }
1409
1410 if (format != getInternalFormat())
1411 {
1412 error(GL_INVALID_OPERATION);
1413 return false;
1414 }
1415
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001416 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001417 {
1418 RECT updateRegion;
1419 updateRegion.left = xoffset;
1420 updateRegion.right = xoffset + width;
1421 updateRegion.bottom = yoffset + height;
1422 updateRegion.top = yoffset;
1423
1424 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001425 HRESULT result = image->lock(&locked, &updateRegion);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001426
1427 if (SUCCEEDED(result))
1428 {
1429 int inputPitch = ComputeCompressedPitch(width, format);
1430 int inputSize = ComputeCompressedSize(width, height, format);
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +00001431 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 +00001432 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001433 }
1434
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001435 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001436 }
1437
1438 return true;
1439}
1440
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001441IDirect3DBaseTexture9 *Texture::getTexture()
1442{
1443 if (!isComplete())
1444 {
1445 return NULL;
1446 }
1447
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001448 if (!getBaseTexture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001449 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001450 createTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001451 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001452
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +00001453 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001454
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001455 return getBaseTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001456}
1457
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001458bool Texture::hasDirtyParameters() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001459{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001460 return mDirtyParameters;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001461}
1462
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001463bool Texture::hasDirtyImages() const
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001464{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001465 return mDirtyImages;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001466}
1467
1468void Texture::resetDirty()
1469{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001470 mDirtyParameters = false;
1471 mDirtyImages = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001472}
1473
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001474unsigned int Texture::getSerial() const
1475{
1476 return mSerial;
1477}
1478
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001479GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1480{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001481 if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001482 {
1483 return maxlevel;
1484 }
1485 else
1486 {
1487 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1488 return 1;
1489 }
1490}
1491
1492GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1493{
1494 return creationLevels(size, size, maxlevel);
1495}
1496
1497int Texture::levelCount() const
1498{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001499 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001500}
1501
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001502unsigned int Texture::issueSerial()
1503{
1504 return mCurrentSerial++;
1505}
1506
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001507Texture2D::Texture2D(GLuint id) : Texture(id)
1508{
1509 mTexture = NULL;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001510 mSurface = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001511}
1512
1513Texture2D::~Texture2D()
1514{
1515 mColorbufferProxy.set(NULL);
1516
1517 if (mTexture)
1518 {
1519 mTexture->Release();
1520 mTexture = NULL;
1521 }
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001522
1523 if (mSurface)
1524 {
1525 mSurface->setBoundTexture(NULL);
1526 mSurface = NULL;
1527 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001528}
1529
1530GLenum Texture2D::getTarget() const
1531{
1532 return GL_TEXTURE_2D;
1533}
1534
daniel@transgaming.com61208202011-03-21 16:38:50 +00001535GLsizei Texture2D::getWidth() const
1536{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001537 return mImageArray[0].getWidth();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001538}
1539
1540GLsizei Texture2D::getHeight() const
1541{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001542 return mImageArray[0].getHeight();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001543}
1544
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001545GLenum Texture2D::getInternalFormat() const
1546{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001547 return mImageArray[0].getFormat();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001548}
1549
daniel@transgaming.com61208202011-03-21 16:38:50 +00001550GLenum Texture2D::getType() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001551{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001552 return mImageArray[0].getType();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001553}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001554
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001555D3DFORMAT Texture2D::getD3DFormat() const
1556{
1557 return mImageArray[0].getD3DFormat();
1558}
1559
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001560void Texture2D::redefineImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.com61208202011-03-21 16:38:50 +00001561{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001562 GLsizei textureWidth = mImageArray[0].getWidth();
1563 GLsizei textureHeight = mImageArray[0].getHeight();
1564 GLenum textureFormat = mImageArray[0].getFormat();
1565 GLenum textureType = mImageArray[0].getType();
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001566
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001567 releaseTexImage();
1568
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001569 mImageArray[level].redefine(format, width, height, type);
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00001570
daniel@transgaming.com61208202011-03-21 16:38:50 +00001571 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001572 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001573 return;
1574 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001575
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001576 bool widthOkay = (textureWidth >> level == width) || (textureWidth >> level == 0 && width == 1);
1577 bool heightOkay = (textureHeight >> level == height) || (textureHeight >> level == 0 && height == 1);
1578 bool textureOkay = (widthOkay && heightOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00001579
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001580 if (!textureOkay)
daniel@transgaming.com61208202011-03-21 16:38:50 +00001581 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001582 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1583 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001584 mImageArray[i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001585 }
1586
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001587 mTexture->Release();
1588 mTexture = NULL;
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00001589 mSerial = 0;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001590 mDirtyImages = true;
apatrick@chromium.org57a2cd62011-06-08 00:04:07 +00001591 mColorbufferProxy.set(NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001592 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001593}
1594
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001595void 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 +00001596{
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001597 redefineImage(level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001598
daniel@transgaming.com61208202011-03-21 16:38:50 +00001599 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001600}
1601
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001602void Texture2D::bindTexImage(egl::Surface *surface)
1603{
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001604 releaseTexImage();
1605
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001606 GLenum format;
1607
1608 switch(surface->getFormat())
1609 {
1610 case D3DFMT_A8R8G8B8:
1611 format = GL_RGBA;
1612 break;
1613 case D3DFMT_X8R8G8B8:
1614 format = GL_RGB;
1615 break;
1616 default:
1617 UNIMPLEMENTED();
1618 return;
1619 }
1620
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001621 mImageArray[0].redefine(format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE);
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001622
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001623 mTexture = surface->getOffscreenTexture();
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00001624 mSerial = issueSerial();
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00001625 mColorbufferProxy.set(NULL);
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001626 mDirtyImages = true;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001627 mIsRenderable = true;
1628 mSurface = surface;
1629 mSurface->setBoundTexture(this);
1630}
1631
1632void Texture2D::releaseTexImage()
1633{
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001634 if (mSurface)
1635 {
1636 mSurface->setBoundTexture(NULL);
1637 mSurface = NULL;
1638
1639 if (mTexture)
1640 {
1641 mTexture->Release();
1642 mTexture = NULL;
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00001643 mSerial = 0;
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00001644 mColorbufferProxy.set(NULL);
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001645 }
1646
1647 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1648 {
1649 mImageArray[i].redefine(GL_RGBA, 0, 0, GL_UNSIGNED_BYTE);
1650 }
1651 }
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001652}
1653
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001654void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001655{
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001656 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001657
daniel@transgaming.com61208202011-03-21 16:38:50 +00001658 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001659}
1660
1661void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1662{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001663 ASSERT(mImageArray[level].getSurface() != NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001664
1665 if (level < levelCount())
1666 {
1667 IDirect3DSurface9 *destLevel = NULL;
1668 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1669
1670 ASSERT(SUCCEEDED(result));
1671
1672 if (SUCCEEDED(result))
1673 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001674 Image *image = &mImageArray[level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001675
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001676 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->getHeight());;
daniel@transgaming.comb612f882011-11-09 17:44:31 +00001677 POINT destPoint = {sourceRect.left, sourceRect.top};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001678
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001679 result = getDevice()->UpdateSurface(image->getSurface(), &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001680 ASSERT(SUCCEEDED(result));
1681
1682 destLevel->Release();
1683
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001684 image->markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001685 }
1686 }
1687}
1688
1689void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1690{
1691 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1692 {
1693 commitRect(level, xoffset, yoffset, width, height);
1694 }
1695}
1696
1697void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1698{
1699 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1700 {
1701 commitRect(level, xoffset, yoffset, width, height);
1702 }
1703}
1704
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001705void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001706{
1707 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1708
1709 if (!renderTarget)
1710 {
1711 ERR("Failed to retrieve the render target.");
1712 return error(GL_OUT_OF_MEMORY);
1713 }
1714
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001715 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001716
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001717 if (!mImageArray[level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001718 {
daniel@transgaming.com90cfcc92011-11-09 17:45:48 +00001719 mImageArray[level].copy(0, 0, x, y, width, height, renderTarget);
1720 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001721 }
1722 else
1723 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001724 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001725 {
1726 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001727 }
daniel@transgaming.com3b3c1d42011-06-08 20:38:09 +00001728
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001729 mImageArray[level].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001730
1731 if (width != 0 && height != 0 && level < levelCount())
1732 {
1733 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1734 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1735 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1736 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1737 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001738
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001739 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[level].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001740
1741 IDirect3DSurface9 *dest;
1742 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1743
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001744 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001745 dest->Release();
1746 }
1747 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001748}
1749
1750void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1751{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001752 if (xoffset + width > mImageArray[level].getWidth() || yoffset + height > mImageArray[level].getHeight())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001753 {
1754 return error(GL_INVALID_VALUE);
1755 }
1756
1757 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1758
1759 if (!renderTarget)
1760 {
1761 ERR("Failed to retrieve the render target.");
1762 return error(GL_OUT_OF_MEMORY);
1763 }
1764
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001765 if (!mImageArray[level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001766 {
daniel@transgaming.com90cfcc92011-11-09 17:45:48 +00001767 mImageArray[level].copy(xoffset, yoffset, x, y, width, height, renderTarget);
1768 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001769 }
1770 else
1771 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001772 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001773 {
1774 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001775 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001776
1777 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001778
1779 if (level < levelCount())
1780 {
1781 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1782 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1783 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1784 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1785 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1786
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001787 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001788
1789 IDirect3DSurface9 *dest;
1790 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1791
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001792 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0].getFormat(), xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001793 dest->Release();
1794 }
1795 }
1796}
1797
1798// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1799bool Texture2D::isComplete() const
1800{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001801 GLsizei width = mImageArray[0].getWidth();
1802 GLsizei height = mImageArray[0].getHeight();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001803
1804 if (width <= 0 || height <= 0)
1805 {
1806 return false;
1807 }
1808
1809 bool mipmapping = false;
1810
1811 switch (mMinFilter)
1812 {
1813 case GL_NEAREST:
1814 case GL_LINEAR:
1815 mipmapping = false;
1816 break;
1817 case GL_NEAREST_MIPMAP_NEAREST:
1818 case GL_LINEAR_MIPMAP_NEAREST:
1819 case GL_NEAREST_MIPMAP_LINEAR:
1820 case GL_LINEAR_MIPMAP_LINEAR:
1821 mipmapping = true;
1822 break;
1823 default: UNREACHABLE();
1824 }
1825
daniel@transgaming.combbeffbb2011-11-09 17:46:11 +00001826 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) ||
1827 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsFloat16LinearFilter()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001828 {
1829 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1830 {
1831 return false;
1832 }
1833 }
1834
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001835 bool npot = getContext()->supportsNonPower2Texture();
1836
1837 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001838 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001839 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
1840 (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1841 {
1842 return false;
1843 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001844 }
1845
1846 if (mipmapping)
1847 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001848 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001849 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001850 if (!isPow2(width) || !isPow2(height))
1851 {
1852 return false;
1853 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001854 }
1855
1856 int q = log2(std::max(width, height));
1857
1858 for (int level = 1; level <= q; level++)
1859 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001860 if (mImageArray[level].getFormat() != mImageArray[0].getFormat())
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].getType() != mImageArray[0].getType())
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001866 {
1867 return false;
1868 }
1869
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001870 if (mImageArray[level].getWidth() != std::max(1, width >> level))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001871 {
1872 return false;
1873 }
1874
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001875 if (mImageArray[level].getHeight() != std::max(1, height >> level))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001876 {
1877 return false;
1878 }
1879 }
1880 }
1881
1882 return true;
1883}
1884
1885bool Texture2D::isCompressed() const
1886{
1887 return IsCompressed(getInternalFormat());
1888}
1889
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001890IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1891{
1892 return mTexture;
1893}
1894
1895// Constructs a Direct3D 9 texture resource from the texture images
1896void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001897{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001898 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001899 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001900 GLint levels = creationLevels(mImageArray[0].getWidth(), mImageArray[0].getHeight(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001901
daniel@transgaming.com61208202011-03-21 16:38:50 +00001902 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001903 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 +00001904
1905 if (FAILED(result))
1906 {
1907 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001908 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001909 }
1910
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001911 if (mTexture)
1912 {
1913 mTexture->Release();
1914 }
1915
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001916 mTexture = texture;
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00001917 mSerial = issueSerial();
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00001918 mColorbufferProxy.set(NULL);
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001919 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001920 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001921}
1922
1923void Texture2D::updateTexture()
1924{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001925 int levels = levelCount();
1926
1927 for (int level = 0; level < levels; level++)
1928 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00001929 Image *image = &mImageArray[level];
1930
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001931 if (image->isDirty())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001932 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001933 commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001934 }
1935 }
1936}
1937
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001938void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001939{
1940 IDirect3DTexture9 *texture = NULL;
1941
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001942 if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001943 {
1944 egl::Display *display = getDisplay();
1945 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001946 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001947 GLint levels = creationLevels(mImageArray[0].getWidth(), mImageArray[0].getHeight(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001948
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001949 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 +00001950
1951 if (FAILED(result))
1952 {
1953 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001954 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001955 }
1956
1957 if (mTexture != NULL)
1958 {
1959 int levels = levelCount();
1960 for (int i = 0; i < levels; i++)
1961 {
1962 IDirect3DSurface9 *source;
1963 result = mTexture->GetSurfaceLevel(i, &source);
1964
1965 if (FAILED(result))
1966 {
1967 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1968
1969 texture->Release();
1970
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001971 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001972 }
1973
1974 IDirect3DSurface9 *dest;
1975 result = texture->GetSurfaceLevel(i, &dest);
1976
1977 if (FAILED(result))
1978 {
1979 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1980
1981 texture->Release();
1982 source->Release();
1983
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001984 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001985 }
1986
1987 display->endScene();
1988 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1989
1990 if (FAILED(result))
1991 {
1992 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1993
1994 texture->Release();
1995 source->Release();
1996 dest->Release();
1997
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001998 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001999 }
2000
2001 source->Release();
2002 dest->Release();
2003 }
2004 }
2005 }
2006
2007 if (mTexture != NULL)
2008 {
2009 mTexture->Release();
2010 }
2011
2012 mTexture = texture;
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00002013 mSerial = issueSerial();
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00002014 mColorbufferProxy.set(NULL);
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002015 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002016 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002017}
2018
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002019void Texture2D::generateMipmaps()
2020{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002021 if (!getContext()->supportsNonPower2Texture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002022 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002023 if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight()))
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002024 {
2025 return error(GL_INVALID_OPERATION);
2026 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002027 }
2028
2029 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002030 unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight()));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002031 for (unsigned int i = 1; i <= q; i++)
2032 {
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00002033 redefineImage(i, mImageArray[0].getFormat(),
2034 std::max(mImageArray[0].getWidth() >> i, 1),
2035 std::max(mImageArray[0].getHeight() >> i, 1),
2036 mImageArray[0].getType());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002037 }
2038
daniel@transgaming.com9d4eac72011-11-09 17:45:53 +00002039 if (mTexture && mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002040 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002041 for (unsigned int i = 1; i <= q; i++)
2042 {
2043 IDirect3DSurface9 *upper = NULL;
2044 IDirect3DSurface9 *lower = NULL;
2045
2046 mTexture->GetSurfaceLevel(i-1, &upper);
2047 mTexture->GetSurfaceLevel(i, &lower);
2048
2049 if (upper != NULL && lower != NULL)
2050 {
2051 getBlitter()->boxFilter(upper, lower);
2052 }
2053
2054 if (upper != NULL) upper->Release();
2055 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002056
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002057 mImageArray[i].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002058 }
2059 }
2060 else
2061 {
2062 for (unsigned int i = 1; i <= q; i++)
2063 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002064 if (mImageArray[i].getSurface() == NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002065 {
2066 return error(GL_OUT_OF_MEMORY);
2067 }
2068
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002069 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 +00002070 {
2071 ERR(" failed to load filter %d to %d.", i - 1, i);
2072 }
2073
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002074 mImageArray[i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002075 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002076 }
2077}
2078
2079Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
2080{
2081 if (target != GL_TEXTURE_2D)
2082 {
2083 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2084 }
2085
2086 if (mColorbufferProxy.get() == NULL)
2087 {
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00002088 mColorbufferProxy.set(new Renderbuffer(id(), new RenderbufferTexture(this, target)));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002089 }
2090
2091 return mColorbufferProxy.get();
2092}
2093
2094IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
2095{
2096 ASSERT(target == GL_TEXTURE_2D);
2097
daniel@transgaming.com9d4eac72011-11-09 17:45:53 +00002098 if (!mTexture || !mIsRenderable)
daniel@transgaming.com61208202011-03-21 16:38:50 +00002099 {
2100 convertToRenderTarget();
2101 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002102
2103 if (mTexture == NULL)
2104 {
2105 return NULL;
2106 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002107
2108 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002109
2110 IDirect3DSurface9 *renderTarget = NULL;
2111 mTexture->GetSurfaceLevel(0, &renderTarget);
2112
2113 return renderTarget;
2114}
2115
2116TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
2117{
2118 mTexture = NULL;
2119}
2120
2121TextureCubeMap::~TextureCubeMap()
2122{
2123 for (int i = 0; i < 6; i++)
2124 {
2125 mFaceProxies[i].set(NULL);
2126 }
2127
2128 if (mTexture)
2129 {
2130 mTexture->Release();
2131 mTexture = NULL;
2132 }
2133}
2134
2135GLenum TextureCubeMap::getTarget() const
2136{
2137 return GL_TEXTURE_CUBE_MAP;
2138}
2139
daniel@transgaming.com61208202011-03-21 16:38:50 +00002140GLsizei TextureCubeMap::getWidth() const
2141{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002142 return mImageArray[0][0].getWidth();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002143}
2144
2145GLsizei TextureCubeMap::getHeight() const
2146{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002147 return mImageArray[0][0].getHeight();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002148}
2149
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002150GLenum TextureCubeMap::getInternalFormat() const
2151{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002152 return mImageArray[0][0].getFormat();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002153}
2154
daniel@transgaming.com61208202011-03-21 16:38:50 +00002155GLenum TextureCubeMap::getType() const
2156{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002157 return mImageArray[0][0].getType();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002158}
2159
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002160D3DFORMAT TextureCubeMap::getD3DFormat() const
2161{
2162 return mImageArray[0][0].getD3DFormat();
2163}
2164
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002165void 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 +00002166{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002167 setImage(0, 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::setImageNegX(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(1, 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::setImagePosY(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(2, 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::setImageNegY(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(3, 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::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002186{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002187 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002188}
2189
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002190void 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 +00002191{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002192 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002193}
2194
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002195void 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 +00002196{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002197 redefineImage(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002198
daniel@transgaming.com61208202011-03-21 16:38:50 +00002199 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002200}
2201
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002202void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002203{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002204 ASSERT(mImageArray[face][level].getSurface() != NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002205
2206 if (level < levelCount())
2207 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002208 IDirect3DSurface9 *destLevel = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002209 ASSERT(destLevel != NULL);
2210
2211 if (destLevel != NULL)
2212 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002213 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002214
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002215 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->getHeight());;
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002216 POINT destPoint = {sourceRect.left, sourceRect.top};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002217
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002218 HRESULT result = getDevice()->UpdateSurface(image->getSurface(), &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002219 ASSERT(SUCCEEDED(result));
2220
2221 destLevel->Release();
2222
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002223 image->markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002224 }
2225 }
2226}
2227
2228void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2229{
2230 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
2231 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002232 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002233 }
2234}
2235
2236void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
2237{
2238 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
2239 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002240 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002241 }
2242}
2243
2244// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
2245bool TextureCubeMap::isComplete() const
2246{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002247 int size = mImageArray[0][0].getWidth();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002248
2249 if (size <= 0)
2250 {
2251 return false;
2252 }
2253
2254 bool mipmapping;
2255
2256 switch (mMinFilter)
2257 {
2258 case GL_NEAREST:
2259 case GL_LINEAR:
2260 mipmapping = false;
2261 break;
2262 case GL_NEAREST_MIPMAP_NEAREST:
2263 case GL_LINEAR_MIPMAP_NEAREST:
2264 case GL_NEAREST_MIPMAP_LINEAR:
2265 case GL_LINEAR_MIPMAP_LINEAR:
2266 mipmapping = true;
2267 break;
2268 default: UNREACHABLE();
2269 }
2270
2271 for (int face = 0; face < 6; face++)
2272 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002273 if (mImageArray[face][0].getWidth() != size || mImageArray[face][0].getHeight() != size)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002274 {
2275 return false;
2276 }
2277 }
2278
daniel@transgaming.combbeffbb2011-11-09 17:46:11 +00002279 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) ||
2280 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsFloat16LinearFilter()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002281 {
2282 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
2283 {
2284 return false;
2285 }
2286 }
2287
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002288 bool npot = getContext()->supportsNonPower2Texture();
2289
2290 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002291 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002292 if ((getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE) && !isPow2(size))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002293 {
2294 return false;
2295 }
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002296 }
2297
2298 if (mipmapping)
2299 {
2300 if (!npot)
2301 {
2302 if (!isPow2(size))
2303 {
2304 return false;
2305 }
2306 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002307
2308 int q = log2(size);
2309
2310 for (int face = 0; face < 6; face++)
2311 {
2312 for (int level = 1; level <= q; level++)
2313 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002314 if (mImageArray[face][level].getFormat() != mImageArray[0][0].getFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002315 {
2316 return false;
2317 }
2318
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002319 if (mImageArray[face][level].getType() != mImageArray[0][0].getType())
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002320 {
2321 return false;
2322 }
2323
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002324 if (mImageArray[face][level].getWidth() != std::max(1, size >> level))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002325 {
2326 return false;
2327 }
2328
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002329 ASSERT(mImageArray[face][level].getHeight() == mImageArray[face][level].getWidth());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002330 }
2331 }
2332 }
2333
2334 return true;
2335}
2336
2337bool TextureCubeMap::isCompressed() const
2338{
2339 return IsCompressed(getInternalFormat());
2340}
2341
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002342IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
2343{
2344 return mTexture;
2345}
2346
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002347// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002348void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002349{
2350 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002351 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002352 GLint levels = creationLevels(mImageArray[0][0].getWidth(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002353
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002354 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002355 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].getWidth(), levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002356
2357 if (FAILED(result))
2358 {
2359 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002360 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002361 }
2362
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002363 if (mTexture)
2364 {
2365 mTexture->Release();
2366 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002367
2368 mTexture = texture;
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00002369 mSerial = issueSerial();
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00002370 for(int face = 0; face < 6; face++) mFaceProxies[face].set(NULL);
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002371 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002372 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002373}
2374
2375void TextureCubeMap::updateTexture()
2376{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002377 for (int face = 0; face < 6; face++)
2378 {
2379 int levels = levelCount();
2380 for (int level = 0; level < levels; level++)
2381 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002382 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002383
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00002384 if (image->isDirty())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002385 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002386 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002387 }
2388 }
2389 }
2390}
2391
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002392void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002393{
2394 IDirect3DCubeTexture9 *texture = NULL;
2395
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002396 if (mImageArray[0][0].getWidth() != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002397 {
2398 egl::Display *display = getDisplay();
2399 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002400 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002401 GLint levels = creationLevels(mImageArray[0][0].getWidth(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002402
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002403 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].getWidth(), levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002404
2405 if (FAILED(result))
2406 {
2407 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002408 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002409 }
2410
2411 if (mTexture != NULL)
2412 {
2413 int levels = levelCount();
2414 for (int f = 0; f < 6; f++)
2415 {
2416 for (int i = 0; i < levels; i++)
2417 {
2418 IDirect3DSurface9 *source;
2419 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2420
2421 if (FAILED(result))
2422 {
2423 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2424
2425 texture->Release();
2426
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002427 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002428 }
2429
2430 IDirect3DSurface9 *dest;
2431 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2432
2433 if (FAILED(result))
2434 {
2435 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2436
2437 texture->Release();
2438 source->Release();
2439
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002440 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002441 }
2442
2443 display->endScene();
2444 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2445
2446 if (FAILED(result))
2447 {
2448 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2449
2450 texture->Release();
2451 source->Release();
2452 dest->Release();
2453
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002454 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002455 }
daniel@transgaming.coma1a86202011-08-09 13:41:08 +00002456
2457 source->Release();
2458 dest->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002459 }
2460 }
2461 }
2462 }
2463
2464 if (mTexture != NULL)
2465 {
2466 mTexture->Release();
2467 }
2468
2469 mTexture = texture;
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00002470 mSerial = issueSerial();
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00002471 for(int face = 0; face < 6; face++) mFaceProxies[face].set(NULL);
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002472 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002473 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002474}
2475
daniel@transgaming.com61208202011-03-21 16:38:50 +00002476void 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 +00002477{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002478 redefineImage(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002479
daniel@transgaming.com61208202011-03-21 16:38:50 +00002480 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002481}
2482
2483unsigned int TextureCubeMap::faceIndex(GLenum face)
2484{
2485 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2486 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2487 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2488 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2489 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2490
2491 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2492}
2493
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002494void TextureCubeMap::redefineImage(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002495{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002496 GLsizei textureWidth = mImageArray[0][0].getWidth();
2497 GLsizei textureHeight = mImageArray[0][0].getHeight();
2498 GLenum textureFormat = mImageArray[0][0].getFormat();
2499 GLenum textureType = mImageArray[0][0].getType();
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002500
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002501 mImageArray[face][level].redefine(format, width, height, type);
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00002502
daniel@transgaming.com61208202011-03-21 16:38:50 +00002503 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002504 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002505 return;
2506 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002507
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002508 bool sizeOkay = (textureWidth >> level == width);
2509 bool textureOkay = (sizeOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002510
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00002511 if (!textureOkay)
daniel@transgaming.com61208202011-03-21 16:38:50 +00002512 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002513 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2514 {
2515 for (int f = 0; f < 6; f++)
2516 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002517 mImageArray[f][i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002518 }
2519 }
2520
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002521 mTexture->Release();
2522 mTexture = NULL;
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00002523 mSerial = 0;
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00002524 for(int face = 0; face < 6; face++) mFaceProxies[face].set(NULL);
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002525 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002526 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002527}
2528
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002529void 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 +00002530{
2531 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2532
2533 if (!renderTarget)
2534 {
2535 ERR("Failed to retrieve the render target.");
2536 return error(GL_OUT_OF_MEMORY);
2537 }
2538
2539 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002540 redefineImage(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002541
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002542 if (!mImageArray[faceindex][level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002543 {
daniel@transgaming.com90cfcc92011-11-09 17:45:48 +00002544 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
2545 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002546 }
2547 else
2548 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002549 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002550 {
2551 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002552 }
daniel@transgaming.com3b3c1d42011-06-08 20:38:09 +00002553
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002554 mImageArray[faceindex][level].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002555
2556 ASSERT(width == height);
2557
2558 if (width > 0 && level < levelCount())
2559 {
2560 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2561 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2562 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2563 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2564 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2565
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002566 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[faceindex][level].getWidth());
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002567
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002568 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2569
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002570 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002571 dest->Release();
2572 }
2573 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002574}
2575
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002576IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum target, unsigned int level)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002577{
2578 if (mTexture == NULL)
2579 {
2580 UNREACHABLE();
2581 return NULL;
2582 }
2583
2584 IDirect3DSurface9 *surface = NULL;
2585
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002586 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), level, &surface);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002587
2588 return (SUCCEEDED(hr)) ? surface : NULL;
2589}
2590
2591void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2592{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002593 GLsizei size = mImageArray[faceIndex(target)][level].getWidth();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002594
2595 if (xoffset + width > size || yoffset + height > size)
2596 {
2597 return error(GL_INVALID_VALUE);
2598 }
2599
2600 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2601
2602 if (!renderTarget)
2603 {
2604 ERR("Failed to retrieve the render target.");
2605 return error(GL_OUT_OF_MEMORY);
2606 }
2607
2608 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com01dae852011-11-09 17:44:53 +00002609
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002610 if (!mImageArray[faceindex][level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002611 {
daniel@transgaming.com90cfcc92011-11-09 17:45:48 +00002612 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
2613 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002614 }
2615 else
2616 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002617 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002618 {
2619 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002620 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002621
2622 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002623
2624 if (level < levelCount())
2625 {
2626 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2627 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2628 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2629 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2630 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2631
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002632 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].getWidth());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002633
2634 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2635
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002636 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0][0].getFormat(), xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002637 dest->Release();
2638 }
2639 }
2640}
2641
2642bool TextureCubeMap::isCubeComplete() const
2643{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002644 if (mImageArray[0][0].getWidth() == 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002645 {
2646 return false;
2647 }
2648
2649 for (unsigned int f = 1; f < 6; f++)
2650 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002651 if (mImageArray[f][0].getWidth() != mImageArray[0][0].getWidth()
2652 || mImageArray[f][0].getFormat() != mImageArray[0][0].getFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002653 {
2654 return false;
2655 }
2656 }
2657
2658 return true;
2659}
2660
2661void TextureCubeMap::generateMipmaps()
2662{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002663 if (!isCubeComplete())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002664 {
2665 return error(GL_INVALID_OPERATION);
2666 }
2667
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002668 if (!getContext()->supportsNonPower2Texture())
2669 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002670 if (!isPow2(mImageArray[0][0].getWidth()))
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002671 {
2672 return error(GL_INVALID_OPERATION);
2673 }
2674 }
2675
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002676 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002677 unsigned int q = log2(mImageArray[0][0].getWidth());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002678 for (unsigned int f = 0; f < 6; f++)
2679 {
2680 for (unsigned int i = 1; i <= q; i++)
2681 {
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00002682 redefineImage(f, i, mImageArray[f][0].getFormat(),
2683 std::max(mImageArray[f][0].getWidth() >> i, 1),
2684 std::max(mImageArray[f][0].getWidth() >> i, 1),
2685 mImageArray[f][0].getType());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002686 }
2687 }
2688
daniel@transgaming.com9d4eac72011-11-09 17:45:53 +00002689 if (mTexture && mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002690 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002691 for (unsigned int f = 0; f < 6; f++)
2692 {
2693 for (unsigned int i = 1; i <= q; i++)
2694 {
2695 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2696 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2697
2698 if (upper != NULL && lower != NULL)
2699 {
2700 getBlitter()->boxFilter(upper, lower);
2701 }
2702
2703 if (upper != NULL) upper->Release();
2704 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002705
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002706 mImageArray[f][i].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002707 }
2708 }
2709 }
2710 else
2711 {
2712 for (unsigned int f = 0; f < 6; f++)
2713 {
2714 for (unsigned int i = 1; i <= q; i++)
2715 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002716 if (mImageArray[f][i].getSurface() == NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002717 {
2718 return error(GL_OUT_OF_MEMORY);
2719 }
2720
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002721 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 +00002722 {
2723 ERR(" failed to load filter %d to %d.", i - 1, i);
2724 }
2725
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002726 mImageArray[f][i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002727 }
2728 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002729 }
2730}
2731
2732Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2733{
2734 if (!IsCubemapTextureTarget(target))
2735 {
2736 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2737 }
2738
2739 unsigned int face = faceIndex(target);
2740
2741 if (mFaceProxies[face].get() == NULL)
2742 {
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00002743 mFaceProxies[face].set(new Renderbuffer(id(), new RenderbufferTexture(this, target)));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002744 }
2745
2746 return mFaceProxies[face].get();
2747}
2748
2749IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2750{
2751 ASSERT(IsCubemapTextureTarget(target));
2752
daniel@transgaming.com9d4eac72011-11-09 17:45:53 +00002753 if (!mTexture || !mIsRenderable)
daniel@transgaming.com61208202011-03-21 16:38:50 +00002754 {
2755 convertToRenderTarget();
2756 }
2757
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002758 if (mTexture == NULL)
2759 {
2760 return NULL;
2761 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002762
2763 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002764
2765 IDirect3DSurface9 *renderTarget = NULL;
2766 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2767
2768 return renderTarget;
2769}
2770
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002771}