blob: 0059669072c27a1ab311cb9a4644dd521be918ee [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +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
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000011#include "libGLESv2/Texture.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000012
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +000013#include <d3dx9tex.h>
14
daniel@transgaming.com16973022010-03-11 19:22:19 +000015#include <algorithm>
16
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000017#include "common/debug.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000018
19#include "libGLESv2/main.h"
20#include "libGLESv2/mathutil.h"
21#include "libGLESv2/utilities.h"
22#include "libGLESv2/Blit.h"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +000023#include "libGLESv2/Framebuffer.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000024
25namespace gl
26{
daniel@transgaming.com842f7a42010-03-21 04:31:03 +000027
28Texture::Image::Image()
daniel@transgaming.com01868132010-08-24 19:21:17 +000029 : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +000030{
31}
32
33Texture::Image::~Image()
34{
35 if (surface) surface->Release();
36}
37
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000038Texture::Texture(GLuint id) : RefCountObject(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000039{
40 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
41 mMagFilter = GL_LINEAR;
42 mWrapS = GL_REPEAT;
43 mWrapT = GL_REPEAT;
daniel@transgaming.com29d27002010-03-11 19:41:22 +000044
daniel@transgaming.com31273552010-08-04 13:42:44 +000045 mWidth = 0;
46 mHeight = 0;
47
daniel@transgaming.com00c75962010-03-11 20:36:15 +000048 mDirtyMetaData = true;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000049 mDirty = true;
daniel@transgaming.com93a81472010-04-20 18:52:58 +000050 mIsRenderable = false;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +000051 mType = GL_UNSIGNED_BYTE;
daniel@transgaming.com0a311a42010-05-17 09:58:33 +000052 mBaseTexture = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000053}
54
55Texture::~Texture()
56{
57}
58
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000059Blit *Texture::getBlitter()
60{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000061 Context *context = getContext();
62 return context->getBlitter();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000063}
64
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000065// Returns true on successful filter state update (valid enum parameter)
66bool Texture::setMinFilter(GLenum filter)
67{
68 switch (filter)
69 {
70 case GL_NEAREST:
71 case GL_LINEAR:
72 case GL_NEAREST_MIPMAP_NEAREST:
73 case GL_LINEAR_MIPMAP_NEAREST:
74 case GL_NEAREST_MIPMAP_LINEAR:
75 case GL_LINEAR_MIPMAP_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000076 {
77 if (mMinFilter != filter)
78 {
79 mMinFilter = filter;
80 mDirty = true;
81 }
82 return true;
83 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000084 default:
85 return false;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +000086 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000087}
88
89// Returns true on successful filter state update (valid enum parameter)
90bool Texture::setMagFilter(GLenum filter)
91{
92 switch (filter)
93 {
94 case GL_NEAREST:
95 case GL_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000096 {
97 if (mMagFilter != filter)
98 {
99 mMagFilter = filter;
100 mDirty = true;
101 }
102 return true;
103 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000104 default:
105 return false;
106 }
107}
108
109// Returns true on successful wrap state update (valid enum parameter)
110bool Texture::setWrapS(GLenum wrap)
111{
112 switch (wrap)
113 {
114 case GL_REPEAT:
115 case GL_CLAMP_TO_EDGE:
116 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000117 {
118 if (mWrapS != wrap)
119 {
120 mWrapS = wrap;
121 mDirty = true;
122 }
123 return true;
124 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000125 default:
126 return false;
127 }
128}
129
130// Returns true on successful wrap state update (valid enum parameter)
131bool Texture::setWrapT(GLenum wrap)
132{
133 switch (wrap)
134 {
135 case GL_REPEAT:
136 case GL_CLAMP_TO_EDGE:
137 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000138 {
139 if (mWrapT != wrap)
140 {
141 mWrapT = wrap;
142 mDirty = true;
143 }
144 return true;
145 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000146 default:
147 return false;
148 }
149}
150
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000151GLenum Texture::getMinFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000152{
153 return mMinFilter;
154}
155
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000156GLenum Texture::getMagFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000157{
158 return mMagFilter;
159}
160
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000161GLenum Texture::getWrapS() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000162{
163 return mWrapS;
164}
165
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000166GLenum Texture::getWrapT() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000167{
168 return mWrapT;
169}
170
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000171GLuint Texture::getWidth() const
172{
173 return mWidth;
174}
175
176GLuint Texture::getHeight() const
177{
178 return mHeight;
179}
180
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000181bool Texture::isFloatingPoint() const
182{
183 return (mType == GL_FLOAT || mType == GL_HALF_FLOAT_OES);
184}
185
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +0000186bool Texture::isRenderableFormat() const
187{
188 D3DFORMAT format = getD3DFormat();
189
190 switch(format)
191 {
192 case D3DFMT_L8:
193 case D3DFMT_A8L8:
194 case D3DFMT_DXT1:
195 return false;
196 case D3DFMT_A8R8G8B8:
apatrick@chromium.org9c857952010-11-16 18:27:58 +0000197 case D3DFMT_X8R8G8B8:
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +0000198 case D3DFMT_A16B16G16R16F:
199 case D3DFMT_A32B32G32R32F:
200 return true;
201 default:
202 UNREACHABLE();
203 }
204
205 return false;
206}
207
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000208// Selects an internal Direct3D 9 format for storing an Image
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000209D3DFORMAT Texture::selectFormat(GLenum format, GLenum type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000210{
daniel@transgaming.com01868132010-08-24 19:21:17 +0000211 if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
212 format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
213 {
214 return D3DFMT_DXT1;
215 }
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000216 else if (type == GL_FLOAT)
217 {
218 return D3DFMT_A32B32G32R32F;
219 }
220 else if (type == GL_HALF_FLOAT_OES)
221 {
222 return D3DFMT_A16B16G16R16F;
223 }
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000224 else if (type == GL_UNSIGNED_BYTE)
daniel@transgaming.com01868132010-08-24 19:21:17 +0000225 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000226 if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
227 {
228 return D3DFMT_L8;
229 }
230 else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
231 {
232 return D3DFMT_A8L8;
233 }
apatrick@chromium.org9c857952010-11-16 18:27:58 +0000234 else if (format == GL_RGB)
235 {
236 return D3DFMT_X8R8G8B8;
237 }
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000238
daniel@transgaming.com01868132010-08-24 19:21:17 +0000239 return D3DFMT_A8R8G8B8;
240 }
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000241
242 return D3DFMT_A8R8G8B8;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000243}
244
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000245// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000246// into the target pixel rectangle at output with outputPitch bytes in between each line.
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000247void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000248 GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000249{
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000250 GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment);
251 input = ((char*)input) - inputPitch * (height - 1);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000252
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000253 switch (type)
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000254 {
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000255 case GL_UNSIGNED_BYTE:
256 switch (format)
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000257 {
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000258 case GL_ALPHA:
259 loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
260 break;
261 case GL_LUMINANCE:
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000262 loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000263 break;
264 case GL_LUMINANCE_ALPHA:
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000265 loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000266 break;
267 case GL_RGB:
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000268 loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
269 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000270 case GL_RGBA:
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000271 loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
272 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000273 case GL_BGRA_EXT:
274 loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000275 break;
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000276 default: UNREACHABLE();
277 }
278 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000279 case GL_UNSIGNED_SHORT_5_6_5:
280 switch (format)
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000281 {
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000282 case GL_RGB:
283 loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000284 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000285 default: UNREACHABLE();
286 }
287 break;
288 case GL_UNSIGNED_SHORT_4_4_4_4:
289 switch (format)
290 {
291 case GL_RGBA:
292 loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
293 break;
294 default: UNREACHABLE();
295 }
296 break;
297 case GL_UNSIGNED_SHORT_5_5_5_1:
298 switch (format)
299 {
300 case GL_RGBA:
301 loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
302 break;
303 default: UNREACHABLE();
304 }
305 break;
306 case GL_FLOAT:
307 switch (format)
308 {
309 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
310 case GL_ALPHA:
311 loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
312 break;
313 case GL_LUMINANCE:
314 loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
315 break;
316 case GL_LUMINANCE_ALPHA:
317 loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
318 break;
319 case GL_RGB:
320 loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
321 break;
322 case GL_RGBA:
323 loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
324 break;
325 default: UNREACHABLE();
326 }
327 break;
328 case GL_HALF_FLOAT_OES:
329 switch (format)
330 {
331 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
332 case GL_ALPHA:
333 loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
334 break;
335 case GL_LUMINANCE:
336 loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
337 break;
338 case GL_LUMINANCE_ALPHA:
339 loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
340 break;
341 case GL_RGB:
342 loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
343 break;
344 case GL_RGBA:
345 loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
346 break;
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000347 default: UNREACHABLE();
348 }
349 break;
350 default: UNREACHABLE();
351 }
352}
353
354void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000355 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000356{
357 const unsigned char *source = NULL;
358 unsigned char *dest = NULL;
359
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000360 for (int y = 0; y < height; y++)
361 {
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000362 source = static_cast<const unsigned char*>(input) + y * inputPitch;
363 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000364 for (int x = 0; x < width; x++)
365 {
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000366 dest[4 * x + 0] = 0;
367 dest[4 * x + 1] = 0;
368 dest[4 * x + 2] = 0;
369 dest[4 * x + 3] = source[x];
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000370 }
371 }
372}
373
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000374void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000375 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000376{
377 const float *source = NULL;
378 float *dest = NULL;
379
380 for (int y = 0; y < height; y++)
381 {
382 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
383 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
384 for (int x = 0; x < width; x++)
385 {
386 dest[4 * x + 0] = 0;
387 dest[4 * x + 1] = 0;
388 dest[4 * x + 2] = 0;
389 dest[4 * x + 3] = source[x];
390 }
391 }
392}
393
394void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000395 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000396{
397 const unsigned short *source = NULL;
398 unsigned short *dest = NULL;
399
400 for (int y = 0; y < height; y++)
401 {
402 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
403 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
404 for (int x = 0; x < width; x++)
405 {
406 dest[4 * x + 0] = 0;
407 dest[4 * x + 1] = 0;
408 dest[4 * x + 2] = 0;
409 dest[4 * x + 3] = source[x];
410 }
411 }
412}
413
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000414void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000415 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000416{
baustin@google.comad5df072011-01-06 21:07:46 +0000417 const int destBytesPerPixel = native? 1: 4;
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000418 const unsigned char *source = NULL;
419 unsigned char *dest = NULL;
420
421 for (int y = 0; y < height; y++)
422 {
423 source = static_cast<const unsigned char*>(input) + y * inputPitch;
baustin@google.comad5df072011-01-06 21:07:46 +0000424 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000425
426 if (!native) // BGRA8 destination format
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000427 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000428 for (int x = 0; x < width; x++)
429 {
430 dest[4 * x + 0] = source[x];
431 dest[4 * x + 1] = source[x];
432 dest[4 * x + 2] = source[x];
433 dest[4 * x + 3] = 0xFF;
434 }
435 }
436 else // L8 destination format
437 {
438 memcpy(dest, source, width);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000439 }
440 }
441}
442
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000443void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000444 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000445{
446 const float *source = NULL;
447 float *dest = NULL;
448
449 for (int y = 0; y < height; y++)
450 {
451 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
452 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
453 for (int x = 0; x < width; x++)
454 {
455 dest[4 * x + 0] = source[x];
456 dest[4 * x + 1] = source[x];
457 dest[4 * x + 2] = source[x];
458 dest[4 * x + 3] = 1.0f;
459 }
460 }
461}
462
463void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000464 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000465{
466 const unsigned short *source = NULL;
467 unsigned short *dest = NULL;
468
469 for (int y = 0; y < height; y++)
470 {
471 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
472 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
473 for (int x = 0; x < width; x++)
474 {
475 dest[4 * x + 0] = source[x];
476 dest[4 * x + 1] = source[x];
477 dest[4 * x + 2] = source[x];
478 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
479 }
480 }
481}
482
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000483void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000484 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000485{
baustin@google.comad5df072011-01-06 21:07:46 +0000486 const int destBytesPerPixel = native? 2: 4;
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000487 const unsigned char *source = NULL;
488 unsigned char *dest = NULL;
489
490 for (int y = 0; y < height; y++)
491 {
492 source = static_cast<const unsigned char*>(input) + y * inputPitch;
baustin@google.comad5df072011-01-06 21:07:46 +0000493 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000494
495 if (!native) // BGRA8 destination format
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000496 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000497 for (int x = 0; x < width; x++)
498 {
499 dest[4 * x + 0] = source[2*x+0];
500 dest[4 * x + 1] = source[2*x+0];
501 dest[4 * x + 2] = source[2*x+0];
502 dest[4 * x + 3] = source[2*x+1];
503 }
504 }
505 else
506 {
507 memcpy(dest, source, width * 2);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000508 }
509 }
510}
511
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000512void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000513 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000514{
515 const float *source = NULL;
516 float *dest = NULL;
517
518 for (int y = 0; y < height; y++)
519 {
520 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
521 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
522 for (int x = 0; x < width; x++)
523 {
524 dest[4 * x + 0] = source[2*x+0];
525 dest[4 * x + 1] = source[2*x+0];
526 dest[4 * x + 2] = source[2*x+0];
527 dest[4 * x + 3] = source[2*x+1];
528 }
529 }
530}
531
532void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000533 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000534{
535 const unsigned short *source = NULL;
536 unsigned short *dest = NULL;
537
538 for (int y = 0; y < height; y++)
539 {
540 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
541 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
542 for (int x = 0; x < width; x++)
543 {
544 dest[4 * x + 0] = source[2*x+0];
545 dest[4 * x + 1] = source[2*x+0];
546 dest[4 * x + 2] = source[2*x+0];
547 dest[4 * x + 3] = source[2*x+1];
548 }
549 }
550}
551
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000552void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000553 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000554{
555 const unsigned char *source = NULL;
556 unsigned char *dest = NULL;
557
558 for (int y = 0; y < height; y++)
559 {
560 source = static_cast<const unsigned char*>(input) + y * inputPitch;
561 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
562 for (int x = 0; x < width; x++)
563 {
564 dest[4 * x + 0] = source[x * 3 + 2];
565 dest[4 * x + 1] = source[x * 3 + 1];
566 dest[4 * x + 2] = source[x * 3 + 0];
567 dest[4 * x + 3] = 0xFF;
568 }
569 }
570}
571
572void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000573 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000574{
575 const unsigned short *source = NULL;
576 unsigned char *dest = NULL;
577
578 for (int y = 0; y < height; y++)
579 {
580 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
581 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
582 for (int x = 0; x < width; x++)
583 {
584 unsigned short rgba = source[x];
585 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
586 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
587 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
588 dest[4 * x + 3] = 0xFF;
589 }
590 }
591}
592
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000593void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000594 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000595{
596 const float *source = NULL;
597 float *dest = NULL;
598
599 for (int y = 0; y < height; y++)
600 {
601 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
602 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
603 for (int x = 0; x < width; x++)
604 {
605 dest[4 * x + 0] = source[x * 3 + 0];
606 dest[4 * x + 1] = source[x * 3 + 1];
607 dest[4 * x + 2] = source[x * 3 + 2];
608 dest[4 * x + 3] = 1.0f;
609 }
610 }
611}
612
613void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000614 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000615{
616 const unsigned short *source = NULL;
617 unsigned short *dest = NULL;
618
619 for (int y = 0; y < height; y++)
620 {
621 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
622 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
623 for (int x = 0; x < width; x++)
624 {
625 dest[4 * x + 0] = source[x * 3 + 0];
626 dest[4 * x + 1] = source[x * 3 + 1];
627 dest[4 * x + 2] = source[x * 3 + 2];
628 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
629 }
630 }
631}
632
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000633void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000634 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000635{
636 const unsigned char *source = NULL;
637 unsigned char *dest = NULL;
638
639 for (int y = 0; y < height; y++)
640 {
641 source = static_cast<const unsigned char*>(input) + y * inputPitch;
642 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
643 for (int x = 0; x < width; x++)
644 {
645 dest[4 * x + 0] = source[x * 4 + 2];
646 dest[4 * x + 1] = source[x * 4 + 1];
647 dest[4 * x + 2] = source[x * 4 + 0];
648 dest[4 * x + 3] = source[x * 4 + 3];
649 }
650 }
651}
652
653void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000654 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000655{
656 const unsigned short *source = NULL;
657 unsigned char *dest = NULL;
658
659 for (int y = 0; y < height; y++)
660 {
661 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
662 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
663 for (int x = 0; x < width; x++)
664 {
665 unsigned short rgba = source[x];
666 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
667 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
668 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
669 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
670 }
671 }
672}
673
674void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000675 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000676{
677 const unsigned short *source = NULL;
678 unsigned char *dest = NULL;
679
680 for (int y = 0; y < height; y++)
681 {
682 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
683 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
684 for (int x = 0; x < width; x++)
685 {
686 unsigned short rgba = source[x];
687 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
688 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
689 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
690 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
691 }
692 }
693}
694
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000695void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000696 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000697{
698 const float *source = NULL;
699 float *dest = NULL;
700
701 for (int y = 0; y < height; y++)
702 {
703 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
704 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
705 memcpy(dest, source, width * 16);
706 }
707}
708
709void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000710 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000711{
712 const unsigned char *source = NULL;
713 unsigned char *dest = NULL;
714
715 for (int y = 0; y < height; y++)
716 {
717 source = static_cast<const unsigned char*>(input) + y * inputPitch;
718 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
719 memcpy(dest, source, width * 8);
720 }
721}
722
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000723void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000724 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000725{
726 const unsigned char *source = NULL;
727 unsigned char *dest = NULL;
728
729 for (int y = 0; y < height; y++)
730 {
731 source = static_cast<const unsigned char*>(input) + y * inputPitch;
732 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
733 memcpy(dest, source, width*4);
734 }
735}
736
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000737void Texture::loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
738 int inputPitch, const void *input, size_t outputPitch, void *output) const
739{
740 ASSERT(xoffset % 4 == 0);
741 ASSERT(yoffset % 4 == 0);
742 ASSERT(width % 4 == 0 || width == 2 || width == 1);
743 ASSERT(inputPitch % 8 == 0);
744 ASSERT(outputPitch % 8 == 0);
745
746 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
747 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
748
749 switch (height)
750 {
751 case 1:
752 // Round width up in case it is 1.
753 for (int x = 0; x < (width + 1) / 2; x += 2)
754 {
755 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
756 dest[x] = source[x];
757
758 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 3 rows being unused. No flipping should occur.
759 dest[x + 1] = source[x + 1];
760 }
761 break;
762 case 2:
763 // Round width up in case it is 1.
764 for (int x = 0; x < (width + 1) / 2; x += 2)
765 {
766 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
767 dest[x] = source[x];
768
769 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 2 rows being unused. Only the top 2 rows should be flipped.
770 dest[x + 1] = ((source[x + 1] << 8) & 0x0000FF00) |
771 ((source[x + 1] >> 8) & 0x000000FF);
772 }
773 break;
774 default:
775 ASSERT(height % 4 == 0);
776 for (int y = 0; y < height / 4; ++y)
777 {
778 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
779 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
780
781 // Round width up in case it is 1.
782 for (int x = 0; x < (width + 1) / 2; x += 2)
783 {
784 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
785 dest[x] = source[x];
786
787 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
788 dest[x + 1] = (source[x + 1] >> 24) |
789 ((source[x + 1] << 8) & 0x00FF0000) |
790 ((source[x + 1] >> 8) & 0x0000FF00) |
791 (source[x + 1] << 24);
792 }
793 }
794 break;
795 }
796}
797
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000798void Texture::createSurface(GLsizei width, GLsizei height, GLenum format, GLenum type, Image *img)
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000799{
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000800 IDirect3DTexture9 *newTexture = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000801 IDirect3DSurface9 *newSurface = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000802
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000803 if (width != 0 && height != 0)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000804 {
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000805 int levelToFetch = 0;
806 GLsizei requestWidth = width;
807 GLsizei requestHeight = height;
808 if (IsCompressed(format) && (width % 4 != 0 || height % 4 != 0))
809 {
810 bool isMult4 = false;
811 int upsampleCount = 0;
812 while (!isMult4)
813 {
814 requestWidth <<= 1;
815 requestHeight <<= 1;
816 upsampleCount++;
817 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
818 {
819 isMult4 = true;
820 }
821 }
822 levelToFetch = upsampleCount;
823 }
824
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000825 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, selectFormat(format, type),
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000826 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000827
828 if (FAILED(result))
829 {
830 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
831 return error(GL_OUT_OF_MEMORY);
832 }
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000833
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000834 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000835 newTexture->Release();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000836 }
837
838 if (img->surface) img->surface->Release();
839 img->surface = newSurface;
840
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000841 img->width = width;
842 img->height = height;
843 img->format = format;
daniel@transgaming.com01868132010-08-24 19:21:17 +0000844}
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000845
daniel@transgaming.com01868132010-08-24 19:21:17 +0000846void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
847{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000848 createSurface(width, height, format, type, img);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000849
850 if (pixels != NULL && img->surface != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000851 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000852 D3DSURFACE_DESC description;
853 img->surface->GetDesc(&description);
854
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000855 D3DLOCKED_RECT locked;
daniel@transgaming.com01868132010-08-24 19:21:17 +0000856 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000857
858 ASSERT(SUCCEEDED(result));
859
860 if (SUCCEEDED(result))
861 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000862 loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000863 img->surface->UnlockRect();
864 }
865
866 img->dirty = true;
867 }
868
869 mDirtyMetaData = true;
870}
871
872void Texture::setCompressedImage(GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
873{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000874 createSurface(width, height, format, GL_UNSIGNED_BYTE, img);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000875
876 if (pixels != NULL && img->surface != NULL)
877 {
878 D3DLOCKED_RECT locked;
879 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
880
881 ASSERT(SUCCEEDED(result));
882
883 if (SUCCEEDED(result))
884 {
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000885 int inputPitch = ComputeCompressedPitch(width, format);
886 int inputSize = ComputeCompressedSize(width, height, format);
887 loadCompressedImageData(0, 0, width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000888 img->surface->UnlockRect();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000889 }
890
891 img->dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000892 }
893
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000894 mDirtyMetaData = true;
895}
896
daniel@transgaming.com31273552010-08-04 13:42:44 +0000897bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000898{
daniel@transgaming.com31273552010-08-04 13:42:44 +0000899 if (width + xoffset > img->width || height + yoffset > img->height)
900 {
901 error(GL_INVALID_VALUE);
902 return false;
903 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000904
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000905 if (!img->surface)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000906 {
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000907 createSurface(img->width, img->height, format, type, img);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000908 }
909
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000910 if (pixels != NULL && img->surface != NULL)
911 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000912 D3DSURFACE_DESC description;
913 img->surface->GetDesc(&description);
914
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000915 D3DLOCKED_RECT locked;
916 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
917
918 ASSERT(SUCCEEDED(result));
919
920 if (SUCCEEDED(result))
921 {
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000922 loadImageData(xoffset, transformPixelYOffset(yoffset, height, img->height), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000923 img->surface->UnlockRect();
924 }
925
926 img->dirty = true;
927 }
928
daniel@transgaming.com31273552010-08-04 13:42:44 +0000929 return true;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000930}
931
daniel@transgaming.com01868132010-08-24 19:21:17 +0000932bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
933{
934 if (width + xoffset > img->width || height + yoffset > img->height)
935 {
936 error(GL_INVALID_VALUE);
937 return false;
938 }
939
940 if (format != getFormat())
941 {
942 error(GL_INVALID_OPERATION);
943 return false;
944 }
945
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000946 if (!img->surface)
daniel@transgaming.com01868132010-08-24 19:21:17 +0000947 {
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000948 createSurface(img->width, img->height, format, GL_UNSIGNED_BYTE, img);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000949 }
950
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000951 if (pixels != NULL && img->surface != NULL)
952 {
953 RECT updateRegion;
954 updateRegion.left = xoffset;
955 updateRegion.right = xoffset + width;
956 updateRegion.bottom = yoffset + height;
957 updateRegion.top = yoffset;
958
959 D3DLOCKED_RECT locked;
960 HRESULT result = img->surface->LockRect(&locked, &updateRegion, 0);
961
962 ASSERT(SUCCEEDED(result));
963
964 if (SUCCEEDED(result))
965 {
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000966 int inputPitch = ComputeCompressedPitch(width, format);
967 int inputSize = ComputeCompressedSize(width, height, format);
968 loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, img->height), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000969 img->surface->UnlockRect();
970 }
971
972 img->dirty = true;
973 }
974
daniel@transgaming.com01868132010-08-24 19:21:17 +0000975 return true;
976}
977
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +0000978// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats
979void Texture::copyNonRenderable(Image *image, GLenum internalFormat, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
980{
981 IDirect3DDevice9 *device = getDevice();
982 IDirect3DSurface9 *surface = NULL;
983 D3DSURFACE_DESC description;
984 renderTarget->GetDesc(&description);
985
986 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
987
988 if (!SUCCEEDED(result))
989 {
990 ERR("Could not create matching destination surface.");
991 return error(GL_OUT_OF_MEMORY);
992 }
993
994 result = device->GetRenderTargetData(renderTarget, surface);
995
996 if (!SUCCEEDED(result))
997 {
998 ERR("GetRenderTargetData unexpectedly failed.");
999 surface->Release();
1000 return error(GL_OUT_OF_MEMORY);
1001 }
1002
1003 D3DLOCKED_RECT sourceLock = {0};
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001004 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001005 result = surface->LockRect(&sourceLock, &sourceRect, 0);
1006
1007 if (FAILED(result))
1008 {
1009 ERR("Failed to lock the source surface (rectangle might be invalid).");
1010 surface->UnlockRect();
1011 surface->Release();
1012 return error(GL_OUT_OF_MEMORY);
1013 }
1014
1015 if (!image->surface)
1016 {
1017 createSurface(width, height, internalFormat, mType, image);
1018 }
1019
1020 if (image->surface == NULL)
1021 {
1022 ERR("Failed to create an image surface.");
1023 surface->UnlockRect();
1024 surface->Release();
1025 return error(GL_OUT_OF_MEMORY);
1026 }
1027
1028 D3DLOCKED_RECT destLock = {0};
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001029 int destYOffset = transformPixelYOffset(yoffset, height, image->height);
1030 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001031 result = image->surface->LockRect(&destLock, &destRect, 0);
1032
1033 if (FAILED(result))
1034 {
1035 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1036 surface->UnlockRect();
1037 surface->Release();
1038 return error(GL_OUT_OF_MEMORY);
1039 }
1040
1041 if (destLock.pBits && sourceLock.pBits)
1042 {
1043 unsigned char *source = (unsigned char*)sourceLock.pBits;
1044 unsigned char *dest = (unsigned char*)destLock.pBits;
1045
1046 switch (description.Format)
1047 {
1048 case D3DFMT_X8R8G8B8:
1049 case D3DFMT_A8R8G8B8:
1050 switch(getD3DFormat())
1051 {
1052 case D3DFMT_L8:
1053 for(int y = 0; y < height; y++)
1054 {
daniel@transgaming.com17767ce2010-12-17 15:57:41 +00001055 for(int x = 0; x < width; x++)
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001056 {
1057 dest[x] = source[x * 4 + 2];
1058 }
1059
1060 source += sourceLock.Pitch;
1061 dest += destLock.Pitch;
1062 }
1063 break;
1064 case D3DFMT_A8L8:
1065 for(int y = 0; y < height; y++)
1066 {
daniel@transgaming.com17767ce2010-12-17 15:57:41 +00001067 for(int x = 0; x < width; x++)
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001068 {
1069 dest[x * 2 + 0] = source[x * 4 + 2];
1070 dest[x * 2 + 1] = source[x * 4 + 3];
1071 }
1072
1073 source += sourceLock.Pitch;
1074 dest += destLock.Pitch;
1075 }
1076 break;
1077 default:
1078 UNREACHABLE();
1079 }
1080 break;
daniel@transgaming.comfe5141e2010-10-18 12:18:12 +00001081 case D3DFMT_R5G6B5:
1082 switch(getD3DFormat())
1083 {
1084 case D3DFMT_L8:
1085 for(int y = 0; y < height; y++)
1086 {
daniel@transgaming.com17767ce2010-12-17 15:57:41 +00001087 for(int x = 0; x < width; x++)
daniel@transgaming.comfe5141e2010-10-18 12:18:12 +00001088 {
1089 unsigned char red = source[x * 2 + 1] & 0xF8;
1090 dest[x] = red | (red >> 5);
1091 }
1092
1093 source += sourceLock.Pitch;
1094 dest += destLock.Pitch;
1095 }
1096 break;
1097 default:
1098 UNREACHABLE();
1099 }
1100 break;
daniel@transgaming.com17767ce2010-12-17 15:57:41 +00001101 case D3DFMT_A1R5G5B5:
1102 switch(getD3DFormat())
1103 {
1104 case D3DFMT_L8:
1105 for(int y = 0; y < height; y++)
1106 {
1107 for(int x = 0; x < width; x++)
1108 {
1109 unsigned char red = source[x * 2 + 1] & 0x7C;
1110 dest[x] = (red << 1) | (red >> 4);
1111 }
1112
1113 source += sourceLock.Pitch;
1114 dest += destLock.Pitch;
1115 }
1116 break;
1117 case D3DFMT_A8L8:
1118 for(int y = 0; y < height; y++)
1119 {
1120 for(int x = 0; x < width; x++)
1121 {
1122 unsigned char red = source[x * 2 + 1] & 0x7C;
1123 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1124 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1125 }
1126
1127 source += sourceLock.Pitch;
1128 dest += destLock.Pitch;
1129 }
1130 break;
1131 default:
1132 UNREACHABLE();
1133 }
1134 break;
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001135 default:
1136 UNREACHABLE();
1137 }
1138
1139 image->dirty = true;
1140 mDirtyMetaData = true;
1141 }
1142
1143 image->surface->UnlockRect();
1144 surface->UnlockRect();
1145 surface->Release();
1146}
1147
enne@chromium.org0fa74632010-09-21 16:18:52 +00001148D3DFORMAT Texture::getD3DFormat() const
1149{
1150 return selectFormat(getFormat(), mType);
1151}
1152
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001153IDirect3DBaseTexture9 *Texture::getTexture()
1154{
1155 if (!isComplete())
1156 {
1157 return NULL;
1158 }
1159
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001160 if (mDirtyMetaData)
1161 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001162 mBaseTexture = createTexture();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001163 mIsRenderable = false;
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001164 }
1165
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001166 if (mDirtyMetaData || dirtyImageData())
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001167 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001168 updateTexture();
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001169 }
1170
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001171 mDirtyMetaData = false;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001172 ASSERT(!dirtyImageData());
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001173
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001174 return mBaseTexture;
1175}
1176
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00001177bool Texture::isDirty() const
1178{
1179 return (mDirty || mDirtyMetaData || dirtyImageData());
1180}
1181
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001182// Returns the top-level texture surface as a render target
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001183void Texture::needRenderTarget()
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001184{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001185 if (!mIsRenderable)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001186 {
1187 mBaseTexture = convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001188 mIsRenderable = true;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001189 }
1190
1191 if (dirtyImageData())
1192 {
1193 updateTexture();
1194 }
1195
1196 mDirtyMetaData = false;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001197}
1198
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001199void Texture::dropTexture()
1200{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001201 if (mBaseTexture)
1202 {
1203 mBaseTexture = NULL;
1204 }
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001205
1206 mIsRenderable = false;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001207}
1208
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001209void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001210{
1211 mBaseTexture = newTexture;
1212 mDirtyMetaData = false;
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001213 mIsRenderable = renderable;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00001214 mDirty = true;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001215}
1216
1217
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001218GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1219{
1220 if (isPow2(width) && isPow2(height))
1221 {
1222 return maxlevel;
1223 }
1224 else
1225 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001226 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1227 return 1;
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001228 }
1229}
1230
1231GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1232{
1233 return creationLevels(size, size, maxlevel);
1234}
1235
1236int Texture::levelCount() const
1237{
1238 return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
1239}
1240
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00001241bool Texture::isRenderable() const
1242{
1243 return mIsRenderable;
1244}
1245
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001246Texture2D::Texture2D(GLuint id) : Texture(id)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001247{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001248 mTexture = NULL;
1249}
1250
1251Texture2D::~Texture2D()
1252{
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001253 mColorbufferProxy.set(NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001254
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001255 if (mTexture)
1256 {
1257 mTexture->Release();
1258 mTexture = NULL;
1259 }
1260}
1261
1262GLenum Texture2D::getTarget() const
1263{
1264 return GL_TEXTURE_2D;
1265}
1266
daniel@transgaming.com01868132010-08-24 19:21:17 +00001267GLenum Texture2D::getFormat() const
1268{
1269 return mImageArray[0].format;
1270}
1271
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001272// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1273// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
1274// Call this when a particular level of the texture must be defined with a specific format, width and height.
1275//
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +00001276// Returns true if the existing texture was unsuitable and had to be destroyed. If so, it will also set
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001277// a new height and width for the texture by working backwards from the given width and height.
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001278bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001279{
1280 bool widthOkay = (mWidth >> level == width);
1281 bool heightOkay = (mHeight >> level == height);
1282
1283 bool sizeOkay = ((widthOkay && heightOkay)
1284 || (widthOkay && mHeight >> level == 0 && height == 1)
1285 || (heightOkay && mWidth >> level == 0 && width == 1));
1286
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001287 bool typeOkay = (type == mType);
1288
1289 bool textureOkay = (sizeOkay && typeOkay && internalFormat == mImageArray[0].format);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001290
1291 if (!textureOkay)
1292 {
1293 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
1294 mImageArray[0].format, mWidth, mHeight,
1295 internalFormat, width, height);
1296
1297 // Purge all the levels and the texture.
1298
daniel@transgaming.com5d752f22010-10-07 13:37:20 +00001299 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001300 {
1301 if (mImageArray[i].surface != NULL)
1302 {
1303 mImageArray[i].dirty = false;
1304
1305 mImageArray[i].surface->Release();
1306 mImageArray[i].surface = NULL;
1307 }
1308 }
1309
1310 if (mTexture != NULL)
1311 {
1312 mTexture->Release();
1313 mTexture = NULL;
1314 dropTexture();
1315 }
1316
1317 mWidth = width << level;
1318 mHeight = height << level;
1319 mImageArray[0].format = internalFormat;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001320 mType = type;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001321 }
1322
1323 return !textureOkay;
1324}
1325
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001326void Texture2D::setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001327{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001328 redefineTexture(level, internalFormat, width, height, type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001329
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001330 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001331}
1332
daniel@transgaming.com01868132010-08-24 19:21:17 +00001333void Texture2D::setCompressedImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1334{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001335 redefineTexture(level, internalFormat, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.com01868132010-08-24 19:21:17 +00001336
1337 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[level]);
1338}
1339
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001340void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1341{
1342 ASSERT(mImageArray[level].surface != NULL);
1343
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001344 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001345 {
1346 IDirect3DSurface9 *destLevel = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001347 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001348
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001349 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001350
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001351 if (SUCCEEDED(result))
1352 {
1353 Image *img = &mImageArray[level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001354
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001355 RECT sourceRect;
1356 sourceRect.left = xoffset;
1357 sourceRect.top = yoffset;
1358 sourceRect.right = xoffset + width;
1359 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001360
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001361 POINT destPoint;
1362 destPoint.x = xoffset;
1363 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001364
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001365 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
1366 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001367
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001368 destLevel->Release();
1369
1370 img->dirty = false;
1371 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001372 }
1373}
1374
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001375void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001376{
daniel@transgaming.com31273552010-08-04 13:42:44 +00001377 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1378 {
1379 commitRect(level, xoffset, yoffset, width, height);
1380 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001381}
1382
daniel@transgaming.com01868132010-08-24 19:21:17 +00001383void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1384{
1385 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1386 {
1387 commitRect(level, xoffset, yoffset, width, height);
1388 }
1389}
1390
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001391void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001392{
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001393 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1394
1395 if (!renderTarget)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001396 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001397 ERR("Failed to retrieve the render target.");
1398 return error(GL_OUT_OF_MEMORY);
1399 }
1400
1401 bool redefined = redefineTexture(level, internalFormat, width, height, mType);
1402
1403 if (!isRenderableFormat())
1404 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001405 copyNonRenderable(&mImageArray[level], internalFormat, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001406 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001407 else
1408 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001409 if (redefined)
1410 {
1411 convertToRenderTarget();
1412 pushTexture(mTexture, true);
1413 }
1414 else
1415 {
1416 needRenderTarget();
1417 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001418
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001419 if (width != 0 && height != 0 && level < levelCount())
1420 {
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001421 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1422 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1423 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1424 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1425 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1426
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001427 IDirect3DSurface9 *dest;
1428 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001429
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001430 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1431 dest->Release();
1432 }
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001433 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001434
1435 mImageArray[level].width = width;
1436 mImageArray[level].height = height;
1437 mImageArray[level].format = internalFormat;
1438}
1439
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001440void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001441{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001442 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1443 {
1444 return error(GL_INVALID_VALUE);
1445 }
1446
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001447 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1448
1449 if (!renderTarget)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001450 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001451 ERR("Failed to retrieve the render target.");
1452 return error(GL_OUT_OF_MEMORY);
1453 }
1454
1455 bool redefined = redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, mType);
1456
1457 if (!isRenderableFormat())
1458 {
1459 copyNonRenderable(&mImageArray[level], getFormat(), xoffset, yoffset, x, y, width, height, renderTarget);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001460 }
1461 else
1462 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001463 if (redefined)
1464 {
1465 convertToRenderTarget();
1466 pushTexture(mTexture, true);
1467 }
1468 else
1469 {
1470 needRenderTarget();
1471 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001472
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001473 if (level < levelCount())
1474 {
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001475 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1476 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1477 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1478 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1479 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1480
1481 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001482
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001483 IDirect3DSurface9 *dest;
1484 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001485
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001486 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001487 dest->Release();
1488 }
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001489 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001490}
1491
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001492// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1493bool Texture2D::isComplete() const
1494{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001495 GLsizei width = mImageArray[0].width;
1496 GLsizei height = mImageArray[0].height;
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001497
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001498 if (width <= 0 || height <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001499 {
1500 return false;
1501 }
1502
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001503 bool mipmapping = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001504
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001505 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001506 {
1507 case GL_NEAREST:
1508 case GL_LINEAR:
1509 mipmapping = false;
1510 break;
1511 case GL_NEAREST_MIPMAP_NEAREST:
1512 case GL_LINEAR_MIPMAP_NEAREST:
1513 case GL_NEAREST_MIPMAP_LINEAR:
1514 case GL_LINEAR_MIPMAP_LINEAR:
1515 mipmapping = true;
1516 break;
1517 default: UNREACHABLE();
1518 }
1519
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001520 if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1521 (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1522 {
1523 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1524 {
1525 return false;
1526 }
1527 }
1528
1529
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001530 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1531 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1532 {
1533 return false;
1534 }
1535
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001536 if (mipmapping)
1537 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001538 if (!isPow2(width) || !isPow2(height))
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001539 {
1540 return false;
1541 }
1542
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001543 int q = log2(std::max(width, height));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001544
1545 for (int level = 1; level <= q; level++)
1546 {
1547 if (mImageArray[level].format != mImageArray[0].format)
1548 {
1549 return false;
1550 }
1551
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001552 if (mImageArray[level].width != std::max(1, width >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001553 {
1554 return false;
1555 }
1556
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001557 if (mImageArray[level].height != std::max(1, height >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001558 {
1559 return false;
1560 }
1561 }
1562 }
1563
1564 return true;
1565}
1566
daniel@transgaming.com01868132010-08-24 19:21:17 +00001567bool Texture2D::isCompressed() const
1568{
1569 return IsCompressed(getFormat());
1570}
1571
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001572// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001573IDirect3DBaseTexture9 *Texture2D::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001574{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001575 IDirect3DTexture9 *texture;
1576
1577 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001578 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001579
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001580 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001581
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001582 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001583 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001584 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001585 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001586 }
1587
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001588 if (mTexture) mTexture->Release();
1589 mTexture = texture;
1590 return texture;
1591}
1592
1593void Texture2D::updateTexture()
1594{
1595 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001596
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001597 int levels = levelCount();
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001598
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001599 for (int level = 0; level < levels; level++)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001600 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001601 if (mImageArray[level].dirty)
1602 {
1603 IDirect3DSurface9 *levelSurface = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001604 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001605
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001606 ASSERT(SUCCEEDED(result));
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001607
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001608 if (SUCCEEDED(result))
1609 {
1610 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1611 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001612
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001613 levelSurface->Release();
1614
1615 mImageArray[level].dirty = false;
1616 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001617 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001618 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001619}
1620
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001621IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001622{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001623 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001624
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001625 if (mWidth != 0 && mHeight != 0)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001626 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001627 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001628 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001629 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001630
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001631 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001632
1633 if (FAILED(result))
1634 {
1635 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1636 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1637 }
1638
1639 if (mTexture != NULL)
1640 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001641 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001642 for (int i = 0; i < levels; i++)
1643 {
1644 IDirect3DSurface9 *source;
1645 result = mTexture->GetSurfaceLevel(i, &source);
1646
1647 if (FAILED(result))
1648 {
1649 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1650
1651 texture->Release();
1652
1653 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1654 }
1655
1656 IDirect3DSurface9 *dest;
1657 result = texture->GetSurfaceLevel(i, &dest);
1658
1659 if (FAILED(result))
1660 {
1661 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1662
1663 texture->Release();
1664 source->Release();
1665
1666 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1667 }
1668
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001669 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001670 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1671
1672 if (FAILED(result))
1673 {
1674 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1675
1676 texture->Release();
1677 source->Release();
1678 dest->Release();
1679
1680 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1681 }
1682
1683 source->Release();
1684 dest->Release();
1685 }
1686 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001687 }
1688
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001689 if (mTexture != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001690 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001691 mTexture->Release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001692 }
1693
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001694 mTexture = texture;
1695 return mTexture;
1696}
1697
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001698bool Texture2D::dirtyImageData() const
1699{
1700 int q = log2(std::max(mWidth, mHeight));
1701
1702 for (int i = 0; i <= q; i++)
1703 {
1704 if (mImageArray[i].dirty) return true;
1705 }
1706
1707 return false;
1708}
1709
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001710void Texture2D::generateMipmaps()
1711{
1712 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1713 {
1714 return error(GL_INVALID_OPERATION);
1715 }
1716
1717 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1718 unsigned int q = log2(std::max(mWidth, mHeight));
1719 for (unsigned int i = 1; i <= q; i++)
1720 {
1721 if (mImageArray[i].surface != NULL)
1722 {
1723 mImageArray[i].surface->Release();
1724 mImageArray[i].surface = NULL;
1725 }
1726
1727 mImageArray[i].dirty = false;
1728
1729 mImageArray[i].format = mImageArray[0].format;
1730 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1731 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
1732 }
1733
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00001734 if (isRenderable())
apatrick@chromium.org9398a6b2010-09-20 19:07:49 +00001735 {
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00001736 if (mTexture == NULL)
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001737 {
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00001738 ERR(" failed because mTexture was null.");
1739 return;
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001740 }
1741
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00001742 for (unsigned int i = 1; i <= q; i++)
1743 {
1744 IDirect3DSurface9 *upper = NULL;
1745 IDirect3DSurface9 *lower = NULL;
1746
1747 mTexture->GetSurfaceLevel(i-1, &upper);
1748 mTexture->GetSurfaceLevel(i, &lower);
1749
1750 if (upper != NULL && lower != NULL)
1751 {
1752 getBlitter()->boxFilter(upper, lower);
1753 }
1754
1755 if (upper != NULL) upper->Release();
1756 if (lower != NULL) lower->Release();
1757 }
1758 }
1759 else
1760 {
1761 for (unsigned int i = 1; i <= q; i++)
1762 {
1763 createSurface(mImageArray[i].width, mImageArray[i].height, mImageArray[i].format, mType, &mImageArray[i]);
1764 if (mImageArray[i].surface == NULL)
1765 {
1766 return error(GL_OUT_OF_MEMORY);
1767 }
1768
1769 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1770 {
1771 ERR(" failed to load filter %d to %d.", i - 1, i);
1772 }
1773
1774 mImageArray[i].dirty = true;
1775 }
1776
1777 mDirtyMetaData = true;
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001778 }
1779}
1780
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001781Renderbuffer *Texture2D::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001782{
1783 if (target != GL_TEXTURE_2D)
1784 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001785 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001786 }
1787
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001788 if (mColorbufferProxy.get() == NULL)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001789 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001790 mColorbufferProxy.set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001791 }
1792
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001793 return mColorbufferProxy.get();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001794}
1795
1796IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1797{
1798 ASSERT(target == GL_TEXTURE_2D);
1799
1800 needRenderTarget();
1801
apatrick@chromium.org4d5962c2010-09-20 19:02:30 +00001802 if (mTexture == NULL)
1803 {
1804 return NULL;
1805 }
1806
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001807 IDirect3DSurface9 *renderTarget = NULL;
1808 mTexture->GetSurfaceLevel(0, &renderTarget);
1809
1810 return renderTarget;
1811}
1812
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001813TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001814{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001815 mTexture = NULL;
1816}
1817
1818TextureCubeMap::~TextureCubeMap()
1819{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001820 for (int i = 0; i < 6; i++)
1821 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001822 mFaceProxies[i].set(NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001823 }
1824
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001825 if (mTexture)
1826 {
1827 mTexture->Release();
1828 mTexture = NULL;
1829 }
1830}
1831
1832GLenum TextureCubeMap::getTarget() const
1833{
1834 return GL_TEXTURE_CUBE_MAP;
1835}
1836
daniel@transgaming.com01868132010-08-24 19:21:17 +00001837GLenum TextureCubeMap::getFormat() const
1838{
1839 return mImageArray[0][0].format;
1840}
1841
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001842void TextureCubeMap::setImagePosX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001843{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001844 setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001845}
1846
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001847void TextureCubeMap::setImageNegX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001848{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001849 setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001850}
1851
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001852void TextureCubeMap::setImagePosY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001853{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001854 setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001855}
1856
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001857void TextureCubeMap::setImageNegY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001858{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001859 setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001860}
1861
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001862void TextureCubeMap::setImagePosZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001863{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001864 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001865}
1866
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001867void TextureCubeMap::setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001868{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001869 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001870}
1871
daniel@transgaming.com01868132010-08-24 19:21:17 +00001872void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1873{
1874 redefineTexture(level, internalFormat, width);
1875
1876 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[faceIndex(face)][level]);
1877}
1878
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001879void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1880{
1881 int face = faceIndex(faceTarget);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001882 ASSERT(mImageArray[face][level].surface != NULL);
1883
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001884 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001885 {
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001886 IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001887 ASSERT(destLevel != NULL);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001888
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001889 if (destLevel != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001890 {
1891 Image *img = &mImageArray[face][level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001892
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001893 RECT sourceRect;
1894 sourceRect.left = xoffset;
1895 sourceRect.top = yoffset;
1896 sourceRect.right = xoffset + width;
1897 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001898
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001899 POINT destPoint;
1900 destPoint.x = xoffset;
1901 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001902
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001903 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001904 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001905
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001906 destLevel->Release();
1907
1908 img->dirty = false;
1909 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001910 }
1911}
1912
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001913void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001914{
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001915 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
daniel@transgaming.com31273552010-08-04 13:42:44 +00001916 {
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001917 commitRect(target, level, xoffset, yoffset, width, height);
daniel@transgaming.com31273552010-08-04 13:42:44 +00001918 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001919}
1920
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001921void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
daniel@transgaming.com01868132010-08-24 19:21:17 +00001922{
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001923 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
daniel@transgaming.com01868132010-08-24 19:21:17 +00001924 {
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001925 commitRect(target, level, xoffset, yoffset, width, height);
daniel@transgaming.com01868132010-08-24 19:21:17 +00001926 }
1927}
1928
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001929// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001930bool TextureCubeMap::isComplete() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001931{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001932 int size = mImageArray[0][0].width;
1933
1934 if (size <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001935 {
1936 return false;
1937 }
1938
1939 bool mipmapping;
1940
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001941 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001942 {
1943 case GL_NEAREST:
1944 case GL_LINEAR:
1945 mipmapping = false;
1946 break;
1947 case GL_NEAREST_MIPMAP_NEAREST:
1948 case GL_LINEAR_MIPMAP_NEAREST:
1949 case GL_NEAREST_MIPMAP_LINEAR:
1950 case GL_LINEAR_MIPMAP_LINEAR:
1951 mipmapping = true;
1952 break;
1953 default: UNREACHABLE();
1954 }
1955
1956 for (int face = 0; face < 6; face++)
1957 {
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001958 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001959 {
1960 return false;
1961 }
1962 }
1963
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001964 if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1965 (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1966 {
1967 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1968 {
1969 return false;
1970 }
1971 }
1972
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001973 if (mipmapping)
1974 {
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001975 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1976 {
1977 return false;
1978 }
1979
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001980 int q = log2(size);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001981
1982 for (int face = 0; face < 6; face++)
1983 {
1984 for (int level = 1; level <= q; level++)
1985 {
1986 if (mImageArray[face][level].format != mImageArray[0][0].format)
1987 {
1988 return false;
1989 }
1990
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001991 if (mImageArray[face][level].width != std::max(1, size >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001992 {
1993 return false;
1994 }
1995
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001996 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001997 }
1998 }
1999 }
2000
2001 return true;
2002}
2003
daniel@transgaming.com01868132010-08-24 19:21:17 +00002004bool TextureCubeMap::isCompressed() const
2005{
2006 return IsCompressed(getFormat());
2007}
2008
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002009// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00002010IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002011{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00002012 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00002013 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00002014
2015 IDirect3DCubeTexture9 *texture;
2016
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00002017 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00002018
daniel@transgaming.com7051b972010-03-21 04:31:07 +00002019 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002020 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00002021 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00002022 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002023 }
2024
daniel@transgaming.com00c75962010-03-11 20:36:15 +00002025 if (mTexture) mTexture->Release();
2026
2027 mTexture = texture;
2028 return mTexture;
2029}
2030
2031void TextureCubeMap::updateTexture()
2032{
2033 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002034
daniel@transgaming.com29d27002010-03-11 19:41:22 +00002035 for (int face = 0; face < 6; face++)
2036 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00002037 int levels = levelCount();
2038 for (int level = 0; level < levels; level++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002039 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00002040 Image *img = &mImageArray[face][level];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002041
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00002042 if (img->dirty)
2043 {
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00002044 IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002045 ASSERT(levelSurface != NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002046
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002047 if (levelSurface != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00002048 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002049 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00002050 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00002051
daniel@transgaming.com7051b972010-03-21 04:31:07 +00002052 levelSurface->Release();
2053
2054 img->dirty = false;
2055 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00002056 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002057 }
2058 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002059}
2060
daniel@transgaming.com7051b972010-03-21 04:31:07 +00002061IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
2062{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002063 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00002064
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002065 if (mWidth != 0)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00002066 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00002067 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002068 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00002069 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002070
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00002071 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002072
2073 if (FAILED(result))
2074 {
2075 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2076 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
2077 }
2078
2079 if (mTexture != NULL)
2080 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00002081 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002082 for (int f = 0; f < 6; f++)
2083 {
2084 for (int i = 0; i < levels; i++)
2085 {
2086 IDirect3DSurface9 *source;
2087 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2088
2089 if (FAILED(result))
2090 {
2091 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2092
2093 texture->Release();
2094
2095 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
2096 }
2097
2098 IDirect3DSurface9 *dest;
2099 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2100
2101 if (FAILED(result))
2102 {
2103 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2104
2105 texture->Release();
2106 source->Release();
2107
2108 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
2109 }
2110
daniel@transgaming.comae072af2010-05-05 18:47:28 +00002111 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002112 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2113
2114 if (FAILED(result))
2115 {
2116 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2117
2118 texture->Release();
2119 source->Release();
2120 dest->Release();
2121
2122 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
2123 }
2124 }
2125 }
2126 }
daniel@transgaming.com7051b972010-03-21 04:31:07 +00002127 }
2128
2129 if (mTexture != NULL)
2130 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00002131 mTexture->Release();
2132 }
2133
2134 mTexture = texture;
2135 return mTexture;
2136}
2137
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00002138void TextureCubeMap::setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002139{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002140 redefineTexture(level, internalFormat, width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002141
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002142 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002143}
daniel@transgaming.com00c75962010-03-11 20:36:15 +00002144
2145unsigned int TextureCubeMap::faceIndex(GLenum face)
2146{
2147 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2148 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2149 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2150 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2151 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2152
2153 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2154}
2155
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00002156bool TextureCubeMap::dirtyImageData() const
2157{
2158 int q = log2(mWidth);
2159
2160 for (int f = 0; f < 6; f++)
2161 {
2162 for (int i = 0; i <= q; i++)
2163 {
2164 if (mImageArray[f][i].dirty) return true;
2165 }
2166 }
2167
2168 return false;
2169}
2170
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002171// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
2172// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
2173// Call this when a particular level of the texture must be defined with a specific format, width and height.
2174//
2175// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
2176// a new size for the texture by working backwards from the given size.
2177bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
2178{
2179 // Are these settings compatible with level 0?
2180 bool sizeOkay = (mImageArray[0][0].width >> level == width);
2181
2182 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
2183
2184 if (!textureOkay)
2185 {
2186 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
2187 mImageArray[0][0].format, mImageArray[0][0].width,
2188 internalFormat, width);
2189
2190 // Purge all the levels and the texture.
daniel@transgaming.com5d752f22010-10-07 13:37:20 +00002191 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002192 {
2193 for (int f = 0; f < 6; f++)
2194 {
2195 if (mImageArray[f][i].surface != NULL)
2196 {
2197 mImageArray[f][i].dirty = false;
2198
2199 mImageArray[f][i].surface->Release();
2200 mImageArray[f][i].surface = NULL;
2201 }
2202 }
2203 }
2204
2205 if (mTexture != NULL)
2206 {
2207 mTexture->Release();
2208 mTexture = NULL;
2209 dropTexture();
2210 }
2211
2212 mWidth = width << level;
2213 mImageArray[0][0].width = width << level;
2214 mHeight = width << level;
2215 mImageArray[0][0].height = width << level;
2216
2217 mImageArray[0][0].format = internalFormat;
2218 }
2219
2220 return !textureOkay;
2221}
2222
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00002223void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002224{
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002225 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002226
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002227 if (!renderTarget)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002228 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002229 ERR("Failed to retrieve the render target.");
2230 return error(GL_OUT_OF_MEMORY);
2231 }
2232
2233 unsigned int faceindex = faceIndex(target);
2234 bool redefined = redefineTexture(level, internalFormat, width);
2235
2236 if (!isRenderableFormat())
2237 {
2238 copyNonRenderable(&mImageArray[faceindex][level], internalFormat, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002239 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00002240 else
2241 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002242 if (redefined)
2243 {
2244 convertToRenderTarget();
2245 pushTexture(mTexture, true);
2246 }
2247 else
2248 {
2249 needRenderTarget();
2250 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002251
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002252 ASSERT(width == height);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002253
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002254 if (width > 0 && level < levelCount())
2255 {
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00002256 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2257 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2258 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2259 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2260 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002261
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002262 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002263
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002264 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
2265 dest->Release();
2266 }
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002267 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002268
2269 mImageArray[faceindex][level].width = width;
2270 mImageArray[faceindex][level].height = height;
2271 mImageArray[faceindex][level].format = internalFormat;
2272}
2273
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00002274IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002275{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002276 if (mTexture == NULL)
2277 {
2278 UNREACHABLE();
2279 return NULL;
2280 }
2281
2282 IDirect3DSurface9 *surface = NULL;
2283
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00002284 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002285
2286 return (SUCCEEDED(hr)) ? surface : NULL;
2287}
2288
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00002289void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002290{
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00002291 GLsizei size = mImageArray[faceIndex(target)][level].width;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002292
2293 if (xoffset + width > size || yoffset + height > size)
2294 {
2295 return error(GL_INVALID_VALUE);
2296 }
2297
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002298 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2299
2300 if (!renderTarget)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002301 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002302 ERR("Failed to retrieve the render target.");
2303 return error(GL_OUT_OF_MEMORY);
2304 }
2305
2306 unsigned int faceindex = faceIndex(target);
2307 bool redefined = redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width);
2308
2309 if (!isRenderableFormat())
2310 {
2311 copyNonRenderable(&mImageArray[faceindex][level], getFormat(), 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002312 }
2313 else
2314 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002315 if (redefined)
2316 {
2317 convertToRenderTarget();
2318 pushTexture(mTexture, true);
2319 }
2320 else
2321 {
2322 needRenderTarget();
2323 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002324
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002325 if (level < levelCount())
2326 {
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00002327 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2328 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2329 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2330 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2331 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2332
2333 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002334
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002335 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002336
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00002337 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002338 dest->Release();
2339 }
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00002340 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002341}
2342
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00002343bool TextureCubeMap::isCubeComplete() const
2344{
2345 if (mImageArray[0][0].width == 0)
2346 {
2347 return false;
2348 }
2349
2350 for (unsigned int f = 1; f < 6; f++)
2351 {
2352 if (mImageArray[f][0].width != mImageArray[0][0].width
2353 || mImageArray[f][0].format != mImageArray[0][0].format)
2354 {
2355 return false;
2356 }
2357 }
2358
2359 return true;
2360}
2361
2362void TextureCubeMap::generateMipmaps()
2363{
2364 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
2365 {
2366 return error(GL_INVALID_OPERATION);
2367 }
2368
2369 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2370 unsigned int q = log2(mImageArray[0][0].width);
2371 for (unsigned int f = 0; f < 6; f++)
2372 {
2373 for (unsigned int i = 1; i <= q; i++)
2374 {
2375 if (mImageArray[f][i].surface != NULL)
2376 {
2377 mImageArray[f][i].surface->Release();
2378 mImageArray[f][i].surface = NULL;
2379 }
2380
2381 mImageArray[f][i].dirty = false;
2382
2383 mImageArray[f][i].format = mImageArray[f][0].format;
2384 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2385 mImageArray[f][i].height = mImageArray[f][i].width;
2386 }
2387 }
2388
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00002389 if (isRenderable())
apatrick@chromium.org9398a6b2010-09-20 19:07:49 +00002390 {
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00002391 if (mTexture == NULL)
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00002392 {
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00002393 return;
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00002394 }
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00002395
2396 for (unsigned int f = 0; f < 6; f++)
2397 {
2398 for (unsigned int i = 1; i <= q; i++)
2399 {
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00002400 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2401 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00002402
2403 if (upper != NULL && lower != NULL)
2404 {
2405 getBlitter()->boxFilter(upper, lower);
2406 }
2407
2408 if (upper != NULL) upper->Release();
2409 if (lower != NULL) lower->Release();
2410 }
2411 }
2412 }
2413 else
2414 {
2415 for (unsigned int f = 0; f < 6; f++)
2416 {
2417 for (unsigned int i = 1; i <= q; i++)
2418 {
2419 createSurface(mImageArray[f][i].width, mImageArray[f][i].height, mImageArray[f][i].format, mType, &mImageArray[f][i]);
2420 if (mImageArray[f][i].surface == NULL)
2421 {
2422 return error(GL_OUT_OF_MEMORY);
2423 }
2424
2425 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2426 {
2427 ERR(" failed to load filter %d to %d.", i - 1, i);
2428 }
2429
2430 mImageArray[f][i].dirty = true;
2431 }
2432 }
2433
2434 mDirtyMetaData = true;
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00002435 }
2436}
2437
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002438Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002439{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002440 if (!IsCubemapTextureTarget(target))
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002441 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002442 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002443 }
2444
2445 unsigned int face = faceIndex(target);
2446
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002447 if (mFaceProxies[face].get() == NULL)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002448 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002449 mFaceProxies[face].set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002450 }
2451
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002452 return mFaceProxies[face].get();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002453}
2454
2455IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2456{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002457 ASSERT(IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002458
2459 needRenderTarget();
daniel@transgaming.come979ead2010-09-23 18:03:14 +00002460
2461 if (mTexture == NULL)
2462 {
2463 return NULL;
apatrick@chromium.org4d5962c2010-09-20 19:02:30 +00002464 }
2465
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002466 IDirect3DSurface9 *renderTarget = NULL;
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00002467 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002468
2469 return renderTarget;
2470}
2471
2472Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
enne@chromium.org0fa74632010-09-21 16:18:52 +00002473 : Colorbuffer(texture), mTexture(texture), mTarget(target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002474{
daniel@transgaming.comedc19182010-10-15 17:57:55 +00002475 ASSERT(IsTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002476}
2477
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002478void Texture::TextureColorbufferProxy::addRef() const
2479{
2480 mTexture->addRef();
2481}
2482
2483void Texture::TextureColorbufferProxy::release() const
2484{
2485 mTexture->release();
2486}
2487
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002488IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
2489{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002490 if (mRenderTarget) mRenderTarget->Release();
2491
2492 mRenderTarget = mTexture->getRenderTarget(mTarget);
2493
2494 return mRenderTarget;
2495}
2496
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002497int Texture::TextureColorbufferProxy::getWidth() const
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002498{
daniel@transgaming.com866f3182010-05-20 19:28:22 +00002499 return mTexture->getWidth();
2500}
2501
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002502int Texture::TextureColorbufferProxy::getHeight() const
daniel@transgaming.com866f3182010-05-20 19:28:22 +00002503{
2504 return mTexture->getHeight();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002505}
2506
daniel@transgaming.com01868132010-08-24 19:21:17 +00002507GLenum Texture::TextureColorbufferProxy::getFormat() const
2508{
2509 return mTexture->getFormat();
2510}
2511
daniel@transgaming.com1297d922010-09-01 15:47:47 +00002512bool Texture::TextureColorbufferProxy::isFloatingPoint() const
2513{
2514 return mTexture->isFloatingPoint();
2515}
2516
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002517}