blob: 29177d20386b6d96e6c53309583486b1b1724d3c [file] [log] [blame]
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Texture.cpp: Implements the gl::Texture class and its derived classes
8// Texture2D and TextureCubeMap. Implements GL texture objects and related
9// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
10
11#include "libGLESv2/Texture.h"
12
kbr@google.com4ab3da02011-01-19 03:00:39 +000013#include <d3dx9tex.h>
14
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +000015#include <algorithm>
zmo@google.com86c3f272011-06-21 02:23:19 +000016#include <intrin.h>
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +000017
18#include "common/debug.h"
19
zmo@google.com86c3f272011-06-21 02:23:19 +000020#include "libEGL/Display.h"
21
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +000022#include "libGLESv2/main.h"
23#include "libGLESv2/mathutil.h"
24#include "libGLESv2/utilities.h"
25#include "libGLESv2/Blit.h"
zmo@google.com86c3f272011-06-21 02:23:19 +000026#include "libGLESv2/Framebuffer.h"
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +000027
28namespace gl
29{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +000030unsigned int TextureStorage::mCurrentTextureSerial = 1;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +000031
cmarrin@apple.com128a99d2012-01-07 01:40:13 +000032static D3DFORMAT ConvertTextureFormatType(GLenum format, GLenum type)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +000033{
zmo@google.com6a8e9d62010-09-02 17:54:23 +000034 if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
35 format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
36 {
37 return D3DFMT_DXT1;
38 }
cmarrin@apple.com128a99d2012-01-07 01:40:13 +000039 else if (format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE)
40 {
41 return D3DFMT_DXT3;
42 }
43 else if (format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE)
44 {
45 return D3DFMT_DXT5;
46 }
kbr@google.com4ab3da02011-01-19 03:00:39 +000047 else if (type == GL_FLOAT)
zmo@google.com6a8e9d62010-09-02 17:54:23 +000048 {
kbr@google.com4ab3da02011-01-19 03:00:39 +000049 return D3DFMT_A32B32G32R32F;
50 }
51 else if (type == GL_HALF_FLOAT_OES)
52 {
53 return D3DFMT_A16B16G16R16F;
54 }
55 else if (type == GL_UNSIGNED_BYTE)
56 {
57 if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
58 {
59 return D3DFMT_L8;
60 }
61 else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
62 {
63 return D3DFMT_A8L8;
64 }
65 else if (format == GL_RGB)
66 {
67 return D3DFMT_X8R8G8B8;
68 }
69
zmo@google.com6a8e9d62010-09-02 17:54:23 +000070 return D3DFMT_A8R8G8B8;
71 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +000072
kbr@google.com4ab3da02011-01-19 03:00:39 +000073 return D3DFMT_A8R8G8B8;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +000074}
75
cmarrin@apple.com128a99d2012-01-07 01:40:13 +000076static bool IsTextureFormatRenderable(D3DFORMAT format)
zmo@google.com86c3f272011-06-21 02:23:19 +000077{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +000078 switch(format)
zmo@google.com86c3f272011-06-21 02:23:19 +000079 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +000080 case D3DFMT_L8:
81 case D3DFMT_A8L8:
82 case D3DFMT_DXT1:
83 case D3DFMT_DXT3:
84 case D3DFMT_DXT5:
zmo@google.com86c3f272011-06-21 02:23:19 +000085 return false;
cmarrin@apple.com128a99d2012-01-07 01:40:13 +000086 case D3DFMT_A8R8G8B8:
87 case D3DFMT_X8R8G8B8:
88 case D3DFMT_A16B16G16R16F:
89 case D3DFMT_A32B32G32R32F:
90 return true;
91 default:
92 UNREACHABLE();
93 }
94
95 return false;
96}
97
98Image::Image()
99{
100 mWidth = 0;
101 mHeight = 0;
102 mFormat = GL_NONE;
103 mType = GL_UNSIGNED_BYTE;
104
105 mSurface = NULL;
106
107 mDirty = false;
108
109 mD3DPool = D3DPOOL_SYSTEMMEM;
110 mD3DFormat = D3DFMT_UNKNOWN;
111}
112
113Image::~Image()
114{
115 if (mSurface)
116 {
117 mSurface->Release();
zmo@google.com86c3f272011-06-21 02:23:19 +0000118 }
119}
120
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000121bool Image::redefine(GLenum format, GLsizei width, GLsizei height, GLenum type, bool forceRelease)
zmo@google.com86c3f272011-06-21 02:23:19 +0000122{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000123 if (mWidth != width ||
124 mHeight != height ||
125 mFormat != format ||
126 mType != type ||
127 forceRelease)
zmo@google.com86c3f272011-06-21 02:23:19 +0000128 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000129 mWidth = width;
130 mHeight = height;
131 mFormat = format;
132 mType = type;
133 // compute the d3d format that will be used
134 mD3DFormat = ConvertTextureFormatType(mFormat, mType);
135
136 if (mSurface)
zmo@google.com86c3f272011-06-21 02:23:19 +0000137 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000138 mSurface->Release();
139 mSurface = NULL;
zmo@google.com86c3f272011-06-21 02:23:19 +0000140 }
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000141
142 return true;
143 }
144
145 return false;
146}
147
148void Image::createSurface()
149{
150 if(mSurface)
151 {
152 return;
153 }
154
155 IDirect3DTexture9 *newTexture = NULL;
156 IDirect3DSurface9 *newSurface = NULL;
157 const D3DPOOL poolToUse = D3DPOOL_SYSTEMMEM;
158
159 if (mWidth != 0 && mHeight != 0)
160 {
161 int levelToFetch = 0;
162 GLsizei requestWidth = mWidth;
163 GLsizei requestHeight = mHeight;
164 if (IsCompressed(mFormat) && (mWidth % 4 != 0 || mHeight % 4 != 0))
165 {
166 bool isMult4 = false;
167 int upsampleCount = 0;
168 while (!isMult4)
169 {
170 requestWidth <<= 1;
171 requestHeight <<= 1;
172 upsampleCount++;
173 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
174 {
175 isMult4 = true;
176 }
177 }
178 levelToFetch = upsampleCount;
179 }
180
181 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, getD3DFormat(),
182 poolToUse, &newTexture, NULL);
183
184 if (FAILED(result))
185 {
186 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
187 ERR("Creating image surface failed.");
188 return error(GL_OUT_OF_MEMORY);
189 }
190
191 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
192 newTexture->Release();
193 }
194
195 mSurface = newSurface;
196 mDirty = false;
197 mD3DPool = poolToUse;
198}
199
200HRESULT Image::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect)
201{
202 createSurface();
203
204 HRESULT result = D3DERR_INVALIDCALL;
205
206 if (mSurface)
207 {
208 result = mSurface->LockRect(lockedRect, rect, 0);
209 ASSERT(SUCCEEDED(result));
210
211 mDirty = true;
212 }
213
214 return result;
215}
216
217void Image::unlock()
218{
219 if (mSurface)
220 {
221 HRESULT result = mSurface->UnlockRect();
222 ASSERT(SUCCEEDED(result));
zmo@google.com86c3f272011-06-21 02:23:19 +0000223 }
224}
225
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000226bool Image::isRenderableFormat() const
227{
228 return IsTextureFormatRenderable(getD3DFormat());
229}
230
231D3DFORMAT Image::getD3DFormat() const
zmo@google.com86c3f272011-06-21 02:23:19 +0000232{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000233 // this should only happen if the image hasn't been redefined first
234 // which would be a bug by the caller
235 ASSERT(mD3DFormat != D3DFMT_UNKNOWN);
236
237 return mD3DFormat;
238}
239
240IDirect3DSurface9 *Image::getSurface()
241{
242 createSurface();
243
244 return mSurface;
245}
246
247void Image::setManagedSurface(IDirect3DSurface9 *surface)
248{
249 if (mSurface)
zmo@google.com86c3f272011-06-21 02:23:19 +0000250 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000251 D3DXLoadSurfaceFromSurface(surface, NULL, NULL, mSurface, NULL, NULL, D3DX_FILTER_BOX, 0);
252 mSurface->Release();
zmo@google.com86c3f272011-06-21 02:23:19 +0000253 }
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000254
255 D3DSURFACE_DESC desc;
256 surface->GetDesc(&desc);
257 ASSERT(desc.Pool == D3DPOOL_MANAGED);
258
259 mSurface = surface;
260 mD3DPool = desc.Pool;
zmo@google.com86c3f272011-06-21 02:23:19 +0000261}
262
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000263void Image::updateSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
zmo@google.com86c3f272011-06-21 02:23:19 +0000264{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000265 IDirect3DSurface9 *sourceSurface = getSurface();
266
267 if (sourceSurface != destSurface)
zmo@google.com86c3f272011-06-21 02:23:19 +0000268 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000269 RECT rect = transformPixelRect(xoffset, yoffset, width, height, mHeight);
270
271 if (mD3DPool == D3DPOOL_MANAGED)
zmo@google.com86c3f272011-06-21 02:23:19 +0000272 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000273 HRESULT result = D3DXLoadSurfaceFromSurface(destSurface, NULL, &rect, sourceSurface, NULL, &rect, D3DX_FILTER_BOX, 0);
274 ASSERT(SUCCEEDED(result));
zmo@google.com86c3f272011-06-21 02:23:19 +0000275 }
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000276 else
277 {
278 // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools
279 POINT point = {rect.left, rect.top};
280 HRESULT result = getDevice()->UpdateSurface(sourceSurface, &rect, destSurface, &point);
281 ASSERT(SUCCEEDED(result));
282 }
zmo@google.com86c3f272011-06-21 02:23:19 +0000283 }
284}
285
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +0000286// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
kbr@google.com4ab3da02011-01-19 03:00:39 +0000287// into the target pixel rectangle at output with outputPitch bytes in between each line.
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000288void Image::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum type,
289 GLint unpackAlignment, const void *input, size_t outputPitch, void *output) const
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +0000290{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000291 GLsizei inputPitch = -ComputePitch(width, mFormat, type, unpackAlignment);
zmo@google.com86c3f272011-06-21 02:23:19 +0000292 input = ((char*)input) - inputPitch * (height - 1);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +0000293
kbr@google.com4ab3da02011-01-19 03:00:39 +0000294 switch (type)
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000295 {
kbr@google.com4ab3da02011-01-19 03:00:39 +0000296 case GL_UNSIGNED_BYTE:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000297 switch (mFormat)
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000298 {
kbr@google.com4ab3da02011-01-19 03:00:39 +0000299 case GL_ALPHA:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000300 loadAlphaData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
kbr@google.com4ab3da02011-01-19 03:00:39 +0000301 break;
302 case GL_LUMINANCE:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000303 loadLuminanceData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, getD3DFormat() == D3DFMT_L8);
kbr@google.com4ab3da02011-01-19 03:00:39 +0000304 break;
305 case GL_LUMINANCE_ALPHA:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000306 loadLuminanceAlphaData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, getD3DFormat() == D3DFMT_A8L8);
kbr@google.com4ab3da02011-01-19 03:00:39 +0000307 break;
308 case GL_RGB:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000309 loadRGBUByteData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000310 break;
kbr@google.com4ab3da02011-01-19 03:00:39 +0000311 case GL_RGBA:
zmo@google.com86c3f272011-06-21 02:23:19 +0000312 if (supportsSSE2())
313 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000314 loadRGBAUByteDataSSE2(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
zmo@google.com86c3f272011-06-21 02:23:19 +0000315 }
316 else
317 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000318 loadRGBAUByteData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
zmo@google.com86c3f272011-06-21 02:23:19 +0000319 }
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000320 break;
kbr@google.com4ab3da02011-01-19 03:00:39 +0000321 case GL_BGRA_EXT:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000322 loadBGRAData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000323 break;
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000324 default: UNREACHABLE();
325 }
326 break;
kbr@google.com4ab3da02011-01-19 03:00:39 +0000327 case GL_UNSIGNED_SHORT_5_6_5:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000328 switch (mFormat)
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000329 {
kbr@google.com4ab3da02011-01-19 03:00:39 +0000330 case GL_RGB:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000331 loadRGB565Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000332 break;
kbr@google.com4ab3da02011-01-19 03:00:39 +0000333 default: UNREACHABLE();
334 }
335 break;
336 case GL_UNSIGNED_SHORT_4_4_4_4:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000337 switch (mFormat)
kbr@google.com4ab3da02011-01-19 03:00:39 +0000338 {
339 case GL_RGBA:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000340 loadRGBA4444Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
kbr@google.com4ab3da02011-01-19 03:00:39 +0000341 break;
342 default: UNREACHABLE();
343 }
344 break;
345 case GL_UNSIGNED_SHORT_5_5_5_1:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000346 switch (mFormat)
kbr@google.com4ab3da02011-01-19 03:00:39 +0000347 {
348 case GL_RGBA:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000349 loadRGBA5551Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
kbr@google.com4ab3da02011-01-19 03:00:39 +0000350 break;
351 default: UNREACHABLE();
352 }
353 break;
354 case GL_FLOAT:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000355 switch (mFormat)
kbr@google.com4ab3da02011-01-19 03:00:39 +0000356 {
357 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
358 case GL_ALPHA:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000359 loadAlphaFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
kbr@google.com4ab3da02011-01-19 03:00:39 +0000360 break;
361 case GL_LUMINANCE:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000362 loadLuminanceFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
kbr@google.com4ab3da02011-01-19 03:00:39 +0000363 break;
364 case GL_LUMINANCE_ALPHA:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000365 loadLuminanceAlphaFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
kbr@google.com4ab3da02011-01-19 03:00:39 +0000366 break;
367 case GL_RGB:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000368 loadRGBFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
kbr@google.com4ab3da02011-01-19 03:00:39 +0000369 break;
370 case GL_RGBA:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000371 loadRGBAFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
kbr@google.com4ab3da02011-01-19 03:00:39 +0000372 break;
373 default: UNREACHABLE();
374 }
375 break;
376 case GL_HALF_FLOAT_OES:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000377 switch (mFormat)
kbr@google.com4ab3da02011-01-19 03:00:39 +0000378 {
379 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
380 case GL_ALPHA:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000381 loadAlphaHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
kbr@google.com4ab3da02011-01-19 03:00:39 +0000382 break;
383 case GL_LUMINANCE:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000384 loadLuminanceHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
kbr@google.com4ab3da02011-01-19 03:00:39 +0000385 break;
386 case GL_LUMINANCE_ALPHA:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000387 loadLuminanceAlphaHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
kbr@google.com4ab3da02011-01-19 03:00:39 +0000388 break;
389 case GL_RGB:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000390 loadRGBHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
kbr@google.com4ab3da02011-01-19 03:00:39 +0000391 break;
392 case GL_RGBA:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000393 loadRGBAHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
kbr@google.com4ab3da02011-01-19 03:00:39 +0000394 break;
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000395 default: UNREACHABLE();
396 }
397 break;
398 default: UNREACHABLE();
399 }
400}
401
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000402void Image::loadAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
403 int inputPitch, const void *input, size_t outputPitch, void *output) const
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000404{
405 const unsigned char *source = NULL;
406 unsigned char *dest = NULL;
407
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +0000408 for (int y = 0; y < height; y++)
409 {
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000410 source = static_cast<const unsigned char*>(input) + y * inputPitch;
411 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +0000412 for (int x = 0; x < width; x++)
413 {
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000414 dest[4 * x + 0] = 0;
415 dest[4 * x + 1] = 0;
416 dest[4 * x + 2] = 0;
417 dest[4 * x + 3] = source[x];
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +0000418 }
419 }
420}
421
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000422void Image::loadAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
423 int inputPitch, const void *input, size_t outputPitch, void *output) const
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +0000424{
kbr@google.com4ab3da02011-01-19 03:00:39 +0000425 const float *source = NULL;
426 float *dest = NULL;
427
428 for (int y = 0; y < height; y++)
429 {
430 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
431 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
432 for (int x = 0; x < width; x++)
433 {
434 dest[4 * x + 0] = 0;
435 dest[4 * x + 1] = 0;
436 dest[4 * x + 2] = 0;
437 dest[4 * x + 3] = source[x];
438 }
439 }
440}
441
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000442void Image::loadAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
443 int inputPitch, const void *input, size_t outputPitch, void *output) const
kbr@google.com4ab3da02011-01-19 03:00:39 +0000444{
445 const unsigned short *source = NULL;
446 unsigned short *dest = NULL;
447
448 for (int y = 0; y < height; y++)
449 {
450 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
451 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
452 for (int x = 0; x < width; x++)
453 {
454 dest[4 * x + 0] = 0;
455 dest[4 * x + 1] = 0;
456 dest[4 * x + 2] = 0;
457 dest[4 * x + 3] = source[x];
458 }
459 }
460}
461
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000462void Image::loadLuminanceData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
463 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
kbr@google.com4ab3da02011-01-19 03:00:39 +0000464{
465 const int destBytesPerPixel = native? 1: 4;
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000466 const unsigned char *source = NULL;
467 unsigned char *dest = NULL;
468
469 for (int y = 0; y < height; y++)
470 {
471 source = static_cast<const unsigned char*>(input) + y * inputPitch;
kbr@google.com4ab3da02011-01-19 03:00:39 +0000472 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
473
474 if (!native) // BGRA8 destination format
475 {
476 for (int x = 0; x < width; x++)
477 {
478 dest[4 * x + 0] = source[x];
479 dest[4 * x + 1] = source[x];
480 dest[4 * x + 2] = source[x];
481 dest[4 * x + 3] = 0xFF;
482 }
483 }
484 else // L8 destination format
485 {
486 memcpy(dest, source, width);
487 }
488 }
489}
490
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000491void Image::loadLuminanceFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
492 int inputPitch, const void *input, size_t outputPitch, void *output) const
kbr@google.com4ab3da02011-01-19 03:00:39 +0000493{
494 const float *source = NULL;
495 float *dest = NULL;
496
497 for (int y = 0; y < height; y++)
498 {
499 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
500 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000501 for (int x = 0; x < width; x++)
502 {
503 dest[4 * x + 0] = source[x];
504 dest[4 * x + 1] = source[x];
505 dest[4 * x + 2] = source[x];
kbr@google.com4ab3da02011-01-19 03:00:39 +0000506 dest[4 * x + 3] = 1.0f;
507 }
508 }
509}
510
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000511void Image::loadLuminanceHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
512 int inputPitch, const void *input, size_t outputPitch, void *output) const
kbr@google.com4ab3da02011-01-19 03:00:39 +0000513{
514 const unsigned short *source = NULL;
515 unsigned short *dest = NULL;
516
517 for (int y = 0; y < height; y++)
518 {
519 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
520 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
521 for (int x = 0; x < width; x++)
522 {
523 dest[4 * x + 0] = source[x];
524 dest[4 * x + 1] = source[x];
525 dest[4 * x + 2] = source[x];
526 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000527 }
528 }
529}
530
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000531void Image::loadLuminanceAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
532 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000533{
kbr@google.com4ab3da02011-01-19 03:00:39 +0000534 const int destBytesPerPixel = native? 2: 4;
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000535 const unsigned char *source = NULL;
536 unsigned char *dest = NULL;
537
538 for (int y = 0; y < height; y++)
539 {
540 source = static_cast<const unsigned char*>(input) + y * inputPitch;
kbr@google.com4ab3da02011-01-19 03:00:39 +0000541 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
542
543 if (!native) // BGRA8 destination format
544 {
545 for (int x = 0; x < width; x++)
546 {
547 dest[4 * x + 0] = source[2*x+0];
548 dest[4 * x + 1] = source[2*x+0];
549 dest[4 * x + 2] = source[2*x+0];
550 dest[4 * x + 3] = source[2*x+1];
551 }
552 }
553 else
554 {
555 memcpy(dest, source, width * 2);
556 }
557 }
558}
559
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000560void Image::loadLuminanceAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
561 int inputPitch, const void *input, size_t outputPitch, void *output) const
kbr@google.com4ab3da02011-01-19 03:00:39 +0000562{
563 const float *source = NULL;
564 float *dest = NULL;
565
566 for (int y = 0; y < height; y++)
567 {
568 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
569 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
570 for (int x = 0; x < width; x++)
571 {
572 dest[4 * x + 0] = source[2*x+0];
573 dest[4 * x + 1] = source[2*x+0];
574 dest[4 * x + 2] = source[2*x+0];
575 dest[4 * x + 3] = source[2*x+1];
576 }
577 }
578}
579
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000580void Image::loadLuminanceAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
581 int inputPitch, const void *input, size_t outputPitch, void *output) const
kbr@google.com4ab3da02011-01-19 03:00:39 +0000582{
583 const unsigned short *source = NULL;
584 unsigned short *dest = NULL;
585
586 for (int y = 0; y < height; y++)
587 {
588 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
589 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000590 for (int x = 0; x < width; x++)
591 {
592 dest[4 * x + 0] = source[2*x+0];
593 dest[4 * x + 1] = source[2*x+0];
594 dest[4 * x + 2] = source[2*x+0];
595 dest[4 * x + 3] = source[2*x+1];
596 }
597 }
598}
599
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000600void Image::loadRGBUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
601 int inputPitch, const void *input, size_t outputPitch, void *output) const
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000602{
603 const unsigned char *source = NULL;
604 unsigned char *dest = NULL;
605
606 for (int y = 0; y < height; y++)
607 {
608 source = static_cast<const unsigned char*>(input) + y * inputPitch;
609 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
610 for (int x = 0; x < width; x++)
611 {
612 dest[4 * x + 0] = source[x * 3 + 2];
613 dest[4 * x + 1] = source[x * 3 + 1];
614 dest[4 * x + 2] = source[x * 3 + 0];
615 dest[4 * x + 3] = 0xFF;
616 }
617 }
618}
619
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000620void Image::loadRGB565Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
621 int inputPitch, const void *input, size_t outputPitch, void *output) const
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000622{
623 const unsigned short *source = NULL;
624 unsigned char *dest = NULL;
625
626 for (int y = 0; y < height; y++)
627 {
628 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
629 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
630 for (int x = 0; x < width; x++)
631 {
632 unsigned short rgba = source[x];
633 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
634 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
635 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
636 dest[4 * x + 3] = 0xFF;
637 }
638 }
639}
640
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000641void Image::loadRGBFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
642 int inputPitch, const void *input, size_t outputPitch, void *output) const
kbr@google.com4ab3da02011-01-19 03:00:39 +0000643{
644 const float *source = NULL;
645 float *dest = NULL;
646
647 for (int y = 0; y < height; y++)
648 {
649 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
650 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
651 for (int x = 0; x < width; x++)
652 {
653 dest[4 * x + 0] = source[x * 3 + 0];
654 dest[4 * x + 1] = source[x * 3 + 1];
655 dest[4 * x + 2] = source[x * 3 + 2];
656 dest[4 * x + 3] = 1.0f;
657 }
658 }
659}
660
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000661void Image::loadRGBHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
662 int inputPitch, const void *input, size_t outputPitch, void *output) const
kbr@google.com4ab3da02011-01-19 03:00:39 +0000663{
664 const unsigned short *source = NULL;
665 unsigned short *dest = NULL;
666
667 for (int y = 0; y < height; y++)
668 {
669 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
670 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
671 for (int x = 0; x < width; x++)
672 {
673 dest[4 * x + 0] = source[x * 3 + 0];
674 dest[4 * x + 1] = source[x * 3 + 1];
675 dest[4 * x + 2] = source[x * 3 + 2];
676 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
677 }
678 }
679}
680
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000681void Image::loadRGBAUByteDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
682 int inputPitch, const void *input, size_t outputPitch, void *output) const
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000683{
zmo@google.com86c3f272011-06-21 02:23:19 +0000684 const unsigned int *source = NULL;
685 unsigned int *dest = NULL;
686 __m128i brMask = _mm_set1_epi32(0x00ff00ff);
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000687
688 for (int y = 0; y < height; y++)
689 {
zmo@google.com86c3f272011-06-21 02:23:19 +0000690 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
691 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
692 int x = 0;
693
694 // Make output writes aligned
695 for (x = 0; ((reinterpret_cast<intptr_t>(&dest[x]) & 15) != 0) && x < width; x++)
696 {
697 unsigned int rgba = source[x];
698 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
699 }
700
701 for (; x + 3 < width; x += 4)
702 {
703 __m128i sourceData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&source[x]));
704 // Mask out g and a, which don't change
705 __m128i gaComponents = _mm_andnot_si128(brMask, sourceData);
706 // Mask out b and r
707 __m128i brComponents = _mm_and_si128(sourceData, brMask);
708 // Swap b and r
709 __m128i brSwapped = _mm_shufflehi_epi16(_mm_shufflelo_epi16(brComponents, _MM_SHUFFLE(2, 3, 0, 1)), _MM_SHUFFLE(2, 3, 0, 1));
710 __m128i result = _mm_or_si128(gaComponents, brSwapped);
711 _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), result);
712 }
713
714 // Perform leftover writes
715 for (; x < width; x++)
716 {
717 unsigned int rgba = source[x];
718 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
719 }
720 }
721}
722
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000723void Image::loadRGBAUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
724 int inputPitch, const void *input, size_t outputPitch, void *output) const
zmo@google.com86c3f272011-06-21 02:23:19 +0000725{
726 const unsigned int *source = NULL;
727 unsigned int *dest = NULL;
728 for (int y = 0; y < height; y++)
729 {
730 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
731 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
732
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000733 for (int x = 0; x < width; x++)
734 {
zmo@google.com86c3f272011-06-21 02:23:19 +0000735 unsigned int rgba = source[x];
736 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000737 }
738 }
739}
740
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000741void Image::loadRGBA4444Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
742 int inputPitch, const void *input, size_t outputPitch, void *output) const
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000743{
744 const unsigned short *source = NULL;
745 unsigned char *dest = NULL;
746
747 for (int y = 0; y < height; y++)
748 {
749 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
750 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
751 for (int x = 0; x < width; x++)
752 {
753 unsigned short rgba = source[x];
754 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
755 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
756 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
757 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
758 }
759 }
760}
761
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000762void Image::loadRGBA5551Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
763 int inputPitch, const void *input, size_t outputPitch, void *output) const
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000764{
765 const unsigned short *source = NULL;
766 unsigned char *dest = NULL;
767
768 for (int y = 0; y < height; y++)
769 {
770 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
771 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
772 for (int x = 0; x < width; x++)
773 {
774 unsigned short rgba = source[x];
775 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
776 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
777 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
778 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
779 }
780 }
781}
782
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000783void Image::loadRGBAFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
784 int inputPitch, const void *input, size_t outputPitch, void *output) const
kbr@google.com4ab3da02011-01-19 03:00:39 +0000785{
786 const float *source = NULL;
787 float *dest = NULL;
788
789 for (int y = 0; y < height; y++)
790 {
791 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
792 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
793 memcpy(dest, source, width * 16);
794 }
795}
796
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000797void Image::loadRGBAHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
798 int inputPitch, const void *input, size_t outputPitch, void *output) const
kbr@google.com4ab3da02011-01-19 03:00:39 +0000799{
800 const unsigned char *source = NULL;
801 unsigned char *dest = NULL;
802
803 for (int y = 0; y < height; y++)
804 {
805 source = static_cast<const unsigned char*>(input) + y * inputPitch;
806 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
807 memcpy(dest, source, width * 8);
808 }
809}
810
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000811void Image::loadBGRAData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
812 int inputPitch, const void *input, size_t outputPitch, void *output) const
zmo@google.com6a8e9d62010-09-02 17:54:23 +0000813{
814 const unsigned char *source = NULL;
815 unsigned char *dest = NULL;
816
817 for (int y = 0; y < height; y++)
818 {
819 source = static_cast<const unsigned char*>(input) + y * inputPitch;
820 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
821 memcpy(dest, source, width*4);
822 }
823}
824
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000825void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
826 int inputPitch, const void *input, size_t outputPitch, void *output) const {
827 switch (getD3DFormat())
828 {
829 case D3DFMT_DXT1:
830 loadDXT1Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
831 break;
832 case D3DFMT_DXT3:
833 loadDXT3Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
834 break;
835 case D3DFMT_DXT5:
836 loadDXT5Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
837 break;
838 }
839}
840
841static void FlipCopyDXT1BlockFull(const unsigned int* source, unsigned int* dest) {
842 // A DXT1 block layout is:
843 // [0-1] color0.
844 // [2-3] color1.
845 // [4-7] color bitmap, 2 bits per pixel.
846 // So each of the 4-7 bytes represents one line, flipping a block is just
847 // flipping those bytes.
848
849 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
850 dest[0] = source[0];
851
852 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
853 dest[1] = (source[1] >> 24) |
854 ((source[1] << 8) & 0x00FF0000) |
855 ((source[1] >> 8) & 0x0000FF00) |
856 (source[1] << 24);
857}
858
859// Flips the first 2 lines of a DXT1 block in the y direction.
860static void FlipCopyDXT1BlockHalf(const unsigned int* source, unsigned int* dest) {
861 // See layout above.
862 dest[0] = source[0];
863 dest[1] = ((source[1] << 8) & 0x0000FF00) |
864 ((source[1] >> 8) & 0x000000FF);
865}
866
867// Flips a full DXT3 block in the y direction.
868static void FlipCopyDXT3BlockFull(const unsigned int* source, unsigned int* dest) {
869 // A DXT3 block layout is:
870 // [0-7] alpha bitmap, 4 bits per pixel.
871 // [8-15] a DXT1 block.
872
873 // First and Second 32 bits are 4bit per pixel alpha and need to be flipped.
874 dest[0] = (source[1] >> 16) | (source[1] << 16);
875 dest[1] = (source[0] >> 16) | (source[0] << 16);
876
877 // And flip the DXT1 block using the above function.
878 FlipCopyDXT1BlockFull(source + 2, dest + 2);
879}
880
881// Flips the first 2 lines of a DXT3 block in the y direction.
882static void FlipCopyDXT3BlockHalf(const unsigned int* source, unsigned int* dest) {
883 // See layout above.
884 dest[0] = (source[1] >> 16) | (source[1] << 16);
885 FlipCopyDXT1BlockHalf(source + 2, dest + 2);
886}
887
888// Flips a full DXT5 block in the y direction.
889static void FlipCopyDXT5BlockFull(const unsigned int* source, unsigned int* dest) {
890 // A DXT5 block layout is:
891 // [0] alpha0.
892 // [1] alpha1.
893 // [2-7] alpha bitmap, 3 bits per pixel.
894 // [8-15] a DXT1 block.
895
896 // The alpha bitmap doesn't easily map lines to bytes, so we have to
897 // interpret it correctly. Extracted from
898 // http://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt :
899 //
900 // The 6 "bits" bytes of the block are decoded into one 48-bit integer:
901 //
902 // bits = bits_0 + 256 * (bits_1 + 256 * (bits_2 + 256 * (bits_3 +
903 // 256 * (bits_4 + 256 * bits_5))))
904 //
905 // bits is a 48-bit unsigned integer, from which a three-bit control code
906 // is extracted for a texel at location (x,y) in the block using:
907 //
908 // code(x,y) = bits[3*(4*y+x)+1..3*(4*y+x)+0]
909 //
910 // where bit 47 is the most significant and bit 0 is the least
911 // significant bit.
912 const unsigned char* sourceBytes = static_cast<const unsigned char*>(static_cast<const void*>(source));
913 unsigned char* destBytes = static_cast<unsigned char*>(static_cast<void*>(dest));
914 unsigned int line_0_1 = sourceBytes[2] + 256 * (sourceBytes[3] + 256 * sourceBytes[4]);
915 unsigned int line_2_3 = sourceBytes[5] + 256 * (sourceBytes[6] + 256 * sourceBytes[7]);
916 // swap lines 0 and 1 in line_0_1.
917 unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) |
918 ((line_0_1 & 0xfff000) >> 12);
919 // swap lines 2 and 3 in line_2_3.
920 unsigned int line_3_2 = ((line_2_3 & 0x000fff) << 12) |
921 ((line_2_3 & 0xfff000) >> 12);
922 destBytes[0] = sourceBytes[0];
923 destBytes[1] = sourceBytes[1];
924 destBytes[2] = line_3_2 & 0xff;
925 destBytes[3] = (line_3_2 & 0xff00) >> 8;
926 destBytes[4] = (line_3_2 & 0xff0000) >> 16;
927 destBytes[5] = line_1_0 & 0xff;
928 destBytes[6] = (line_1_0 & 0xff00) >> 8;
929 destBytes[7] = (line_1_0 & 0xff0000) >> 16;
930
931 // And flip the DXT1 block using the above function.
932 FlipCopyDXT1BlockFull(source + 2, dest + 2);
933}
934
935// Flips the first 2 lines of a DXT5 block in the y direction.
936static void FlipCopyDXT5BlockHalf(const unsigned int* source, unsigned int* dest) {
937 // See layout above.
938 const unsigned char* sourceBytes = static_cast<const unsigned char*>(static_cast<const void*>(source));
939 unsigned char* destBytes = static_cast<unsigned char*>(static_cast<void*>(dest));
940 unsigned int line_0_1 = sourceBytes[2] + 256 * (sourceBytes[3] + 256 * sourceBytes[4]);
941 unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) |
942 ((line_0_1 & 0xfff000) >> 12);
943 destBytes[0] = sourceBytes[0];
944 destBytes[1] = sourceBytes[1];
945 destBytes[2] = line_1_0 & 0xff;
946 destBytes[3] = (line_1_0 & 0xff00) >> 8;
947 destBytes[4] = (line_1_0 & 0xff0000) >> 16;
948 FlipCopyDXT1BlockHalf(source + 2, dest + 2);
949}
950
951void Image::loadDXT1Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
952 int inputPitch, const void *input, size_t outputPitch, void *output) const
zmo@google.com86c3f272011-06-21 02:23:19 +0000953{
954 ASSERT(xoffset % 4 == 0);
955 ASSERT(yoffset % 4 == 0);
956 ASSERT(width % 4 == 0 || width == 2 || width == 1);
957 ASSERT(inputPitch % 8 == 0);
958 ASSERT(outputPitch % 8 == 0);
959
960 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
961 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
962
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000963 // Round width up in case it is less than 4.
964 int blocksAcross = (width + 3) / 4;
965 int intsAcross = blocksAcross * 2;
966
zmo@google.com86c3f272011-06-21 02:23:19 +0000967 switch (height)
968 {
969 case 1:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000970 for (int x = 0; x < intsAcross; x += 2)
zmo@google.com86c3f272011-06-21 02:23:19 +0000971 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000972 // just copy the block
zmo@google.com86c3f272011-06-21 02:23:19 +0000973 dest[x] = source[x];
zmo@google.com86c3f272011-06-21 02:23:19 +0000974 dest[x + 1] = source[x + 1];
975 }
976 break;
977 case 2:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000978 for (int x = 0; x < intsAcross; x += 2)
zmo@google.com86c3f272011-06-21 02:23:19 +0000979 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000980 FlipCopyDXT1BlockHalf(source + x, dest + x);
zmo@google.com86c3f272011-06-21 02:23:19 +0000981 }
982 break;
983 default:
984 ASSERT(height % 4 == 0);
985 for (int y = 0; y < height / 4; ++y)
986 {
987 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
988 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
989
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000990 for (int x = 0; x < intsAcross; x += 2)
zmo@google.com86c3f272011-06-21 02:23:19 +0000991 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000992 FlipCopyDXT1BlockFull(source + x, dest + x);
zmo@google.com86c3f272011-06-21 02:23:19 +0000993 }
994 }
995 break;
996 }
997}
998
cmarrin@apple.com128a99d2012-01-07 01:40:13 +0000999void Image::loadDXT3Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
1000 int inputPitch, const void *input, size_t outputPitch, void *output) const
zmo@google.com6a8e9d62010-09-02 17:54:23 +00001001{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001002 ASSERT(xoffset % 4 == 0);
1003 ASSERT(yoffset % 4 == 0);
1004 ASSERT(width % 4 == 0 || width == 2 || width == 1);
1005 ASSERT(inputPitch % 16 == 0);
1006 ASSERT(outputPitch % 16 == 0);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001007
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001008 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
1009 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
1010
1011 // Round width up in case it is less than 4.
1012 int blocksAcross = (width + 3) / 4;
1013 int intsAcross = blocksAcross * 4;
1014
1015 switch (height)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001016 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001017 case 1:
1018 for (int x = 0; x < intsAcross; x += 4)
zmo@google.com6a8e9d62010-09-02 17:54:23 +00001019 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001020 // just copy the block
1021 dest[x] = source[x];
1022 dest[x + 1] = source[x + 1];
1023 dest[x + 2] = source[x + 2];
1024 dest[x + 3] = source[x + 3];
1025 }
1026 break;
1027 case 2:
1028 for (int x = 0; x < intsAcross; x += 4)
1029 {
1030 FlipCopyDXT3BlockHalf(source + x, dest + x);
1031 }
1032 break;
1033 default:
1034 ASSERT(height % 4 == 0);
1035 for (int y = 0; y < height / 4; ++y)
1036 {
1037 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
1038 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
1039
1040 for (int x = 0; x < intsAcross; x += 4)
zmo@google.com6a8e9d62010-09-02 17:54:23 +00001041 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001042 FlipCopyDXT3BlockFull(source + x, dest + x);
zmo@google.com6a8e9d62010-09-02 17:54:23 +00001043 }
1044 }
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001045 break;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001046 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001047}
1048
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001049void Image::loadDXT5Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
1050 int inputPitch, const void *input, size_t outputPitch, void *output) const
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001051{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001052 ASSERT(xoffset % 4 == 0);
1053 ASSERT(yoffset % 4 == 0);
1054 ASSERT(width % 4 == 0 || width == 2 || width == 1);
1055 ASSERT(inputPitch % 16 == 0);
1056 ASSERT(outputPitch % 16 == 0);
zmo@google.com6a8e9d62010-09-02 17:54:23 +00001057
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001058 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
1059 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
1060
1061 // Round width up in case it is less than 4.
1062 int blocksAcross = (width + 3) / 4;
1063 int intsAcross = blocksAcross * 4;
1064
1065 switch (height)
zmo@google.com6a8e9d62010-09-02 17:54:23 +00001066 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001067 case 1:
1068 for (int x = 0; x < intsAcross; x += 4)
1069 {
1070 // just copy the block
1071 dest[x] = source[x];
1072 dest[x + 1] = source[x + 1];
1073 dest[x + 2] = source[x + 2];
1074 dest[x + 3] = source[x + 3];
1075 }
1076 break;
1077 case 2:
1078 for (int x = 0; x < intsAcross; x += 4)
1079 {
1080 FlipCopyDXT5BlockHalf(source + x, dest + x);
1081 }
1082 break;
1083 default:
1084 ASSERT(height % 4 == 0);
1085 for (int y = 0; y < height / 4; ++y)
1086 {
1087 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
1088 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
zmo@google.com6a8e9d62010-09-02 17:54:23 +00001089
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001090 for (int x = 0; x < intsAcross; x += 4)
1091 {
1092 FlipCopyDXT5BlockFull(source + x, dest + x);
1093 }
1094 }
1095 break;
zmo@google.com6a8e9d62010-09-02 17:54:23 +00001096 }
zmo@google.com6a8e9d62010-09-02 17:54:23 +00001097}
1098
zmo@google.com86c3f272011-06-21 02:23:19 +00001099// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001100void Image::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
kbr@google.com4ab3da02011-01-19 03:00:39 +00001101{
1102 IDirect3DDevice9 *device = getDevice();
zmo@google.com86c3f272011-06-21 02:23:19 +00001103 IDirect3DSurface9 *renderTargetData = NULL;
kbr@google.com4ab3da02011-01-19 03:00:39 +00001104 D3DSURFACE_DESC description;
1105 renderTarget->GetDesc(&description);
1106
zmo@google.com86c3f272011-06-21 02:23:19 +00001107 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
kbr@google.com4ab3da02011-01-19 03:00:39 +00001108
zmo@google.com86c3f272011-06-21 02:23:19 +00001109 if (FAILED(result))
kbr@google.com4ab3da02011-01-19 03:00:39 +00001110 {
1111 ERR("Could not create matching destination surface.");
1112 return error(GL_OUT_OF_MEMORY);
1113 }
1114
zmo@google.com86c3f272011-06-21 02:23:19 +00001115 result = device->GetRenderTargetData(renderTarget, renderTargetData);
kbr@google.com4ab3da02011-01-19 03:00:39 +00001116
zmo@google.com86c3f272011-06-21 02:23:19 +00001117 if (FAILED(result))
kbr@google.com4ab3da02011-01-19 03:00:39 +00001118 {
1119 ERR("GetRenderTargetData unexpectedly failed.");
zmo@google.com86c3f272011-06-21 02:23:19 +00001120 renderTargetData->Release();
kbr@google.com4ab3da02011-01-19 03:00:39 +00001121 return error(GL_OUT_OF_MEMORY);
1122 }
1123
zmo@google.com86c3f272011-06-21 02:23:19 +00001124 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001125 int destYOffset = transformPixelYOffset(yoffset, height, mHeight);
zmo@google.com86c3f272011-06-21 02:23:19 +00001126 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
kbr@google.com4ab3da02011-01-19 03:00:39 +00001127
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001128 if (isRenderableFormat())
kbr@google.com4ab3da02011-01-19 03:00:39 +00001129 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001130 result = D3DXLoadSurfaceFromSurface(getSurface(), NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0);
zmo@google.com86c3f272011-06-21 02:23:19 +00001131
1132 if (FAILED(result))
kbr@google.com4ab3da02011-01-19 03:00:39 +00001133 {
zmo@google.com86c3f272011-06-21 02:23:19 +00001134 ERR("Copying surfaces unexpectedly failed.");
1135 renderTargetData->Release();
1136 return error(GL_OUT_OF_MEMORY);
1137 }
1138 }
1139 else
1140 {
1141 D3DLOCKED_RECT sourceLock = {0};
1142 result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
kbr@google.com4ab3da02011-01-19 03:00:39 +00001143
zmo@google.com86c3f272011-06-21 02:23:19 +00001144 if (FAILED(result))
1145 {
1146 ERR("Failed to lock the source surface (rectangle might be invalid).");
1147 renderTargetData->Release();
1148 return error(GL_OUT_OF_MEMORY);
kbr@google.com4ab3da02011-01-19 03:00:39 +00001149 }
1150
zmo@google.com86c3f272011-06-21 02:23:19 +00001151 D3DLOCKED_RECT destLock = {0};
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001152 result = lock(&destLock, &destRect);
zmo@google.com86c3f272011-06-21 02:23:19 +00001153
1154 if (FAILED(result))
1155 {
1156 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1157 renderTargetData->UnlockRect();
1158 renderTargetData->Release();
1159 return error(GL_OUT_OF_MEMORY);
1160 }
1161
1162 if (destLock.pBits && sourceLock.pBits)
1163 {
1164 unsigned char *source = (unsigned char*)sourceLock.pBits;
1165 unsigned char *dest = (unsigned char*)destLock.pBits;
1166
1167 switch (description.Format)
1168 {
1169 case D3DFMT_X8R8G8B8:
1170 case D3DFMT_A8R8G8B8:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001171 switch(getD3DFormat())
zmo@google.com86c3f272011-06-21 02:23:19 +00001172 {
1173 case D3DFMT_L8:
1174 for(int y = 0; y < height; y++)
1175 {
1176 for(int x = 0; x < width; x++)
1177 {
1178 dest[x] = source[x * 4 + 2];
1179 }
1180
1181 source += sourceLock.Pitch;
1182 dest += destLock.Pitch;
1183 }
1184 break;
1185 case D3DFMT_A8L8:
1186 for(int y = 0; y < height; y++)
1187 {
1188 for(int x = 0; x < width; x++)
1189 {
1190 dest[x * 2 + 0] = source[x * 4 + 2];
1191 dest[x * 2 + 1] = source[x * 4 + 3];
1192 }
1193
1194 source += sourceLock.Pitch;
1195 dest += destLock.Pitch;
1196 }
1197 break;
1198 default:
1199 UNREACHABLE();
1200 }
1201 break;
1202 case D3DFMT_R5G6B5:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001203 switch(getD3DFormat())
zmo@google.com86c3f272011-06-21 02:23:19 +00001204 {
1205 case D3DFMT_L8:
1206 for(int y = 0; y < height; y++)
1207 {
1208 for(int x = 0; x < width; x++)
1209 {
1210 unsigned char red = source[x * 2 + 1] & 0xF8;
1211 dest[x] = red | (red >> 5);
1212 }
1213
1214 source += sourceLock.Pitch;
1215 dest += destLock.Pitch;
1216 }
1217 break;
1218 default:
1219 UNREACHABLE();
1220 }
1221 break;
1222 case D3DFMT_A1R5G5B5:
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001223 switch(getD3DFormat())
zmo@google.com86c3f272011-06-21 02:23:19 +00001224 {
1225 case D3DFMT_L8:
1226 for(int y = 0; y < height; y++)
1227 {
1228 for(int x = 0; x < width; x++)
1229 {
1230 unsigned char red = source[x * 2 + 1] & 0x7C;
1231 dest[x] = (red << 1) | (red >> 4);
1232 }
1233
1234 source += sourceLock.Pitch;
1235 dest += destLock.Pitch;
1236 }
1237 break;
1238 case D3DFMT_A8L8:
1239 for(int y = 0; y < height; y++)
1240 {
1241 for(int x = 0; x < width; x++)
1242 {
1243 unsigned char red = source[x * 2 + 1] & 0x7C;
1244 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1245 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1246 }
1247
1248 source += sourceLock.Pitch;
1249 dest += destLock.Pitch;
1250 }
1251 break;
1252 default:
1253 UNREACHABLE();
1254 }
1255 break;
1256 default:
1257 UNREACHABLE();
1258 }
1259 }
1260
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001261 unlock();
zmo@google.com86c3f272011-06-21 02:23:19 +00001262 renderTargetData->UnlockRect();
kbr@google.com4ab3da02011-01-19 03:00:39 +00001263 }
1264
zmo@google.com86c3f272011-06-21 02:23:19 +00001265 renderTargetData->Release();
kbr@google.com4ab3da02011-01-19 03:00:39 +00001266
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001267 mDirty = true;
1268}
1269
1270TextureStorage::TextureStorage(bool renderTarget)
1271 : mRenderTarget(renderTarget),
1272 mD3DPool(getDisplay()->getTexturePool(mRenderTarget)),
1273 mTextureSerial(issueTextureSerial())
1274{
1275}
1276
1277TextureStorage::~TextureStorage()
1278{
1279}
1280
1281bool TextureStorage::isRenderTarget() const
1282{
1283 return mRenderTarget;
1284}
1285
1286bool TextureStorage::isManaged() const
1287{
1288 return (mD3DPool == D3DPOOL_MANAGED);
1289}
1290
1291D3DPOOL TextureStorage::getPool() const
1292{
1293 return mD3DPool;
1294}
1295
1296unsigned int TextureStorage::getTextureSerial() const
1297{
1298 return mTextureSerial;
1299}
1300
1301unsigned int TextureStorage::issueTextureSerial()
1302{
1303 return mCurrentTextureSerial++;
1304}
1305
1306Texture::Texture(GLuint id) : RefCountObject(id)
1307{
1308 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
1309 mMagFilter = GL_LINEAR;
1310 mWrapS = GL_REPEAT;
1311 mWrapT = GL_REPEAT;
1312 mDirtyParameters = true;
1313 mUsage = GL_NONE;
1314
1315 mDirtyImages = true;
1316
1317 mImmutable = false;
1318}
1319
1320Texture::~Texture()
1321{
1322}
1323
1324// Returns true on successful filter state update (valid enum parameter)
1325bool Texture::setMinFilter(GLenum filter)
1326{
1327 switch (filter)
1328 {
1329 case GL_NEAREST:
1330 case GL_LINEAR:
1331 case GL_NEAREST_MIPMAP_NEAREST:
1332 case GL_LINEAR_MIPMAP_NEAREST:
1333 case GL_NEAREST_MIPMAP_LINEAR:
1334 case GL_LINEAR_MIPMAP_LINEAR:
1335 {
1336 if (mMinFilter != filter)
1337 {
1338 mMinFilter = filter;
1339 mDirtyParameters = true;
1340 }
1341 return true;
1342 }
1343 default:
1344 return false;
1345 }
1346}
1347
1348// Returns true on successful filter state update (valid enum parameter)
1349bool Texture::setMagFilter(GLenum filter)
1350{
1351 switch (filter)
1352 {
1353 case GL_NEAREST:
1354 case GL_LINEAR:
1355 {
1356 if (mMagFilter != filter)
1357 {
1358 mMagFilter = filter;
1359 mDirtyParameters = true;
1360 }
1361 return true;
1362 }
1363 default:
1364 return false;
1365 }
1366}
1367
1368// Returns true on successful wrap state update (valid enum parameter)
1369bool Texture::setWrapS(GLenum wrap)
1370{
1371 switch (wrap)
1372 {
1373 case GL_REPEAT:
1374 case GL_CLAMP_TO_EDGE:
1375 case GL_MIRRORED_REPEAT:
1376 {
1377 if (mWrapS != wrap)
1378 {
1379 mWrapS = wrap;
1380 mDirtyParameters = true;
1381 }
1382 return true;
1383 }
1384 default:
1385 return false;
1386 }
1387}
1388
1389// Returns true on successful wrap state update (valid enum parameter)
1390bool Texture::setWrapT(GLenum wrap)
1391{
1392 switch (wrap)
1393 {
1394 case GL_REPEAT:
1395 case GL_CLAMP_TO_EDGE:
1396 case GL_MIRRORED_REPEAT:
1397 {
1398 if (mWrapT != wrap)
1399 {
1400 mWrapT = wrap;
1401 mDirtyParameters = true;
1402 }
1403 return true;
1404 }
1405 default:
1406 return false;
1407 }
1408}
1409
1410// Returns true on successful usage state update (valid enum parameter)
1411bool Texture::setUsage(GLenum usage)
1412{
1413 switch (usage)
1414 {
1415 case GL_NONE:
1416 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
1417 mUsage = usage;
1418 return true;
1419 default:
1420 return false;
1421 }
1422}
1423
1424GLenum Texture::getMinFilter() const
1425{
1426 return mMinFilter;
1427}
1428
1429GLenum Texture::getMagFilter() const
1430{
1431 return mMagFilter;
1432}
1433
1434GLenum Texture::getWrapS() const
1435{
1436 return mWrapS;
1437}
1438
1439GLenum Texture::getWrapT() const
1440{
1441 return mWrapT;
1442}
1443
1444GLenum Texture::getUsage() const
1445{
1446 return mUsage;
1447}
1448
1449void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
1450{
1451 if (pixels != NULL)
1452 {
1453 D3DLOCKED_RECT locked;
1454 HRESULT result = image->lock(&locked, NULL);
1455
1456 if (SUCCEEDED(result))
1457 {
1458 image->loadData(0, 0, image->getWidth(), image->getHeight(), image->getType(), unpackAlignment, pixels, locked.Pitch, locked.pBits);
1459 image->unlock();
1460 }
1461
1462 mDirtyImages = true;
1463 }
1464}
1465
1466void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
1467{
1468 if (pixels != NULL)
1469 {
1470 D3DLOCKED_RECT locked;
1471 HRESULT result = image->lock(&locked, NULL);
1472
1473 if (SUCCEEDED(result))
1474 {
1475 int inputPitch = ComputeCompressedPitch(image->getWidth(), image->getFormat());
1476 int inputSize = ComputeCompressedSize(image->getWidth(), image->getHeight(), image->getFormat());
1477 image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
1478 image->unlock();
1479 }
1480
1481 mDirtyImages = true;
1482 }
1483}
1484
1485bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image)
1486{
1487 if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
1488 {
1489 error(GL_INVALID_VALUE);
1490 return false;
1491 }
1492
1493 if (IsCompressed(image->getFormat()))
1494 {
1495 error(GL_INVALID_OPERATION);
1496 return false;
1497 }
1498
1499 if (format != image->getFormat())
1500 {
1501 error(GL_INVALID_OPERATION);
1502 return false;
1503 }
1504
1505 if (pixels != NULL)
1506 {
1507 D3DLOCKED_RECT locked;
1508 HRESULT result = image->lock(&locked, NULL);
1509
1510 if (SUCCEEDED(result))
1511 {
1512 image->loadData(xoffset, transformPixelYOffset(yoffset, height, image->getHeight()), width, height, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
1513 image->unlock();
1514 }
1515
1516 mDirtyImages = true;
1517 }
1518
1519 return true;
1520}
1521
1522bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image)
1523{
1524 if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
1525 {
1526 error(GL_INVALID_VALUE);
1527 return false;
1528 }
1529
1530 if (format != getInternalFormat())
1531 {
1532 error(GL_INVALID_OPERATION);
1533 return false;
1534 }
1535
1536 if (pixels != NULL)
1537 {
1538 RECT updateRegion;
1539 updateRegion.left = xoffset;
1540 updateRegion.right = xoffset + width;
1541 updateRegion.bottom = yoffset + height;
1542 updateRegion.top = yoffset;
1543
1544 D3DLOCKED_RECT locked;
1545 HRESULT result = image->lock(&locked, &updateRegion);
1546
1547 if (SUCCEEDED(result))
1548 {
1549 int inputPitch = ComputeCompressedPitch(width, format);
1550 int inputSize = ComputeCompressedSize(width, height, format);
1551 image->loadCompressedData(xoffset, transformPixelYOffset(yoffset, height, image->getHeight()), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
1552 image->unlock();
1553 }
1554
1555 mDirtyImages = true;
1556 }
1557
1558 return true;
kbr@google.com4ab3da02011-01-19 03:00:39 +00001559}
1560
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001561IDirect3DBaseTexture9 *Texture::getTexture()
1562{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001563 if (!isSamplerComplete())
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001564 {
1565 return NULL;
1566 }
1567
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001568 // ensure the underlying texture is created
1569 if (getStorage(false) == NULL)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001570 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001571 return NULL;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001572 }
1573
zmo@google.com86c3f272011-06-21 02:23:19 +00001574 updateTexture();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001575
zmo@google.com86c3f272011-06-21 02:23:19 +00001576 return getBaseTexture();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001577}
1578
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001579bool Texture::hasDirtyParameters() const
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001580{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001581 return mDirtyParameters;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001582}
1583
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001584bool Texture::hasDirtyImages() const
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001585{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001586 return mDirtyImages;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001587}
1588
zmo@google.com86c3f272011-06-21 02:23:19 +00001589void Texture::resetDirty()
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001590{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001591 mDirtyParameters = false;
1592 mDirtyImages = false;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001593}
1594
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001595unsigned int Texture::getTextureSerial()
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001596{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001597 TextureStorage *texture = getStorage(false);
1598 return texture ? texture->getTextureSerial() : 0;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001599}
1600
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001601unsigned int Texture::getRenderTargetSerial(GLenum target)
1602{
1603 TextureStorage *texture = getStorage(true);
1604 return texture ? texture->getRenderTargetSerial(target) : 0;
1605}
1606
1607bool Texture::isImmutable() const
1608{
1609 return mImmutable;
1610}
1611
1612GLint Texture::creationLevels(GLsizei width, GLsizei height) const
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001613{
zmo@google.com86c3f272011-06-21 02:23:19 +00001614 if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture())
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001615 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001616 return 0; // Maximum number of levels
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001617 }
1618 else
1619 {
1620 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1621 return 1;
1622 }
1623}
1624
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001625GLint Texture::creationLevels(GLsizei size) const
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001626{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001627 return creationLevels(size, size);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001628}
1629
1630int Texture::levelCount() const
1631{
zmo@google.com86c3f272011-06-21 02:23:19 +00001632 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001633}
1634
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001635Blit *Texture::getBlitter()
kbr@google.com4ab3da02011-01-19 03:00:39 +00001636{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001637 Context *context = getContext();
1638 return context->getBlitter();
1639}
1640
1641bool Texture::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged)
1642{
1643 if (source && dest)
1644 {
1645 HRESULT result;
1646
1647 if (fromManaged)
1648 {
1649 result = D3DXLoadSurfaceFromSurface(dest, NULL, NULL, source, NULL, NULL, D3DX_FILTER_BOX, 0);
1650 }
1651 else
1652 {
1653 egl::Display *display = getDisplay();
1654 IDirect3DDevice9 *device = display->getDevice();
1655
1656 display->endScene();
1657 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1658 }
1659
1660 if (FAILED(result))
1661 {
1662 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1663 return false;
1664 }
1665 }
1666
1667 return true;
1668}
1669
1670TextureStorage2D::TextureStorage2D(IDirect3DTexture9 *surfaceTexture) : TextureStorage(true), mRenderTargetSerial(RenderbufferStorage::issueSerial())
1671{
1672 mTexture = surfaceTexture;
1673}
1674
1675TextureStorage2D::TextureStorage2D(int levels, D3DFORMAT format, int width, int height, bool renderTarget)
1676 : TextureStorage(renderTarget), mRenderTargetSerial(RenderbufferStorage::issueSerial())
1677{
1678 IDirect3DDevice9 *device = getDevice();
1679
1680 mTexture = NULL;
1681 HRESULT result = device->CreateTexture(width, height, levels, isRenderTarget() ? D3DUSAGE_RENDERTARGET : 0, format, getPool(), &mTexture, NULL);
1682
1683 if (FAILED(result))
1684 {
1685 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1686 error(GL_OUT_OF_MEMORY);
1687 }
1688}
1689
1690TextureStorage2D::~TextureStorage2D()
1691{
1692 if (mTexture)
1693 {
1694 mTexture->Release();
1695 }
1696}
1697
1698IDirect3DSurface9 *TextureStorage2D::getSurfaceLevel(int level)
1699{
1700 IDirect3DSurface9 *surface = NULL;
1701
1702 if (mTexture)
1703 {
1704 HRESULT result = mTexture->GetSurfaceLevel(level, &surface);
1705 ASSERT(SUCCEEDED(result));
1706 }
1707
1708 return surface;
1709}
1710
1711IDirect3DBaseTexture9 *TextureStorage2D::getBaseTexture() const
1712{
1713 return mTexture;
1714}
1715
1716unsigned int TextureStorage2D::getRenderTargetSerial(GLenum target) const
1717{
1718 return mRenderTargetSerial;
kbr@google.com4ab3da02011-01-19 03:00:39 +00001719}
1720
zmo@google.com6a8e9d62010-09-02 17:54:23 +00001721Texture2D::Texture2D(GLuint id) : Texture(id)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001722{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001723 mTexStorage = NULL;
zmo@google.com86c3f272011-06-21 02:23:19 +00001724 mSurface = NULL;
dino@apple.comc93dbb32012-03-27 19:19:18 +00001725 mColorbufferProxy = NULL;
1726 mProxyRefs = 0;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001727}
1728
1729Texture2D::~Texture2D()
1730{
dino@apple.comc93dbb32012-03-27 19:19:18 +00001731 mColorbufferProxy = NULL;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001732
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001733 delete mTexStorage;
1734 mTexStorage = NULL;
1735
zmo@google.com86c3f272011-06-21 02:23:19 +00001736 if (mSurface)
1737 {
1738 mSurface->setBoundTexture(NULL);
1739 mSurface = NULL;
1740 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001741}
1742
dino@apple.comc93dbb32012-03-27 19:19:18 +00001743// We need to maintain a count of references to renderbuffers acting as
1744// proxies for this texture, so that we do not attempt to use a pointer
1745// to a renderbuffer proxy which has been deleted.
1746void Texture2D::addProxyRef(const Renderbuffer *proxy)
1747{
1748 mProxyRefs++;
1749}
1750
1751void Texture2D::releaseProxy(const Renderbuffer *proxy)
1752{
1753 if (mProxyRefs > 0)
1754 mProxyRefs--;
1755
1756 if (mProxyRefs == 0)
1757 mColorbufferProxy = NULL;
1758}
1759
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001760GLenum Texture2D::getTarget() const
1761{
1762 return GL_TEXTURE_2D;
1763}
1764
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001765GLsizei Texture2D::getWidth(GLint level) const
zmo@google.com86c3f272011-06-21 02:23:19 +00001766{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001767 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1768 return mImageArray[level].getWidth();
1769 else
1770 return 0;
zmo@google.com86c3f272011-06-21 02:23:19 +00001771}
1772
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001773GLsizei Texture2D::getHeight(GLint level) const
zmo@google.com86c3f272011-06-21 02:23:19 +00001774{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001775 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1776 return mImageArray[level].getHeight();
1777 else
1778 return 0;
zmo@google.com86c3f272011-06-21 02:23:19 +00001779}
1780
1781GLenum Texture2D::getInternalFormat() const
zmo@google.com6a8e9d62010-09-02 17:54:23 +00001782{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001783 return mImageArray[0].getFormat();
zmo@google.com6a8e9d62010-09-02 17:54:23 +00001784}
1785
zmo@google.com86c3f272011-06-21 02:23:19 +00001786GLenum Texture2D::getType() const
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001787{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001788 return mImageArray[0].getType();
zmo@google.com86c3f272011-06-21 02:23:19 +00001789}
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001790
zmo@google.com86c3f272011-06-21 02:23:19 +00001791D3DFORMAT Texture2D::getD3DFormat() const
1792{
1793 return mImageArray[0].getD3DFormat();
1794}
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001795
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001796void Texture2D::redefineImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
zmo@google.com86c3f272011-06-21 02:23:19 +00001797{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001798 releaseTexImage();
kbr@google.com4ab3da02011-01-19 03:00:39 +00001799
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001800 bool redefined = mImageArray[level].redefine(format, width, height, type, false);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001801
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001802 if (mTexStorage && redefined)
zmo@google.com86c3f272011-06-21 02:23:19 +00001803 {
kbr@google.com4ab3da02011-01-19 03:00:39 +00001804 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001805 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001806 mImageArray[i].markDirty();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001807 }
1808
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001809 delete mTexStorage;
1810 mTexStorage = NULL;
1811 mDirtyImages = true;
zmo@google.com86c3f272011-06-21 02:23:19 +00001812 }
1813}
1814
1815void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1816{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001817 redefineImage(level, format, width, height, type);
zmo@google.com86c3f272011-06-21 02:23:19 +00001818
1819 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
1820}
1821
1822void Texture2D::bindTexImage(egl::Surface *surface)
1823{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001824 releaseTexImage();
1825
zmo@google.com86c3f272011-06-21 02:23:19 +00001826 GLenum format;
1827
1828 switch(surface->getFormat())
1829 {
1830 case D3DFMT_A8R8G8B8:
1831 format = GL_RGBA;
1832 break;
1833 case D3DFMT_X8R8G8B8:
1834 format = GL_RGB;
1835 break;
1836 default:
1837 UNIMPLEMENTED();
1838 return;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001839 }
1840
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001841 mImageArray[0].redefine(format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE, true);
zmo@google.com86c3f272011-06-21 02:23:19 +00001842
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001843 delete mTexStorage;
1844 mTexStorage = new TextureStorage2D(surface->getOffscreenTexture());
zmo@google.com86c3f272011-06-21 02:23:19 +00001845
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001846 mDirtyImages = true;
zmo@google.com86c3f272011-06-21 02:23:19 +00001847 mSurface = surface;
1848 mSurface->setBoundTexture(this);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001849}
1850
zmo@google.com86c3f272011-06-21 02:23:19 +00001851void Texture2D::releaseTexImage()
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001852{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001853 if (mSurface)
1854 {
1855 mSurface->setBoundTexture(NULL);
1856 mSurface = NULL;
1857
1858 if (mTexStorage)
1859 {
1860 delete mTexStorage;
1861 mTexStorage = NULL;
1862 }
1863
1864 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1865 {
1866 mImageArray[i].redefine(GL_RGBA, 0, 0, GL_UNSIGNED_BYTE, true);
1867 }
1868 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001869}
1870
zmo@google.com86c3f272011-06-21 02:23:19 +00001871void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
zmo@google.com6a8e9d62010-09-02 17:54:23 +00001872{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001873 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE);
zmo@google.com6a8e9d62010-09-02 17:54:23 +00001874
zmo@google.com86c3f272011-06-21 02:23:19 +00001875 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
zmo@google.com6a8e9d62010-09-02 17:54:23 +00001876}
1877
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001878void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1879{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001880 ASSERT(mImageArray[level].getSurface() != NULL);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001881
1882 if (level < levelCount())
1883 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001884 IDirect3DSurface9 *destLevel = mTexStorage->getSurfaceLevel(level);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001885
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001886 if (destLevel)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001887 {
zmo@google.com86c3f272011-06-21 02:23:19 +00001888 Image *image = &mImageArray[level];
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001889 image->updateSurface(destLevel, xoffset, yoffset, width, height);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001890
1891 destLevel->Release();
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001892 image->markClean();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001893 }
1894 }
1895}
1896
1897void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1898{
zmo@google.com6a8e9d62010-09-02 17:54:23 +00001899 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1900 {
1901 commitRect(level, xoffset, yoffset, width, height);
1902 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001903}
1904
zmo@google.com6a8e9d62010-09-02 17:54:23 +00001905void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1906{
1907 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1908 {
1909 commitRect(level, xoffset, yoffset, width, height);
1910 }
1911}
1912
zmo@google.com86c3f272011-06-21 02:23:19 +00001913void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001914{
kbr@google.com4ab3da02011-01-19 03:00:39 +00001915 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1916
1917 if (!renderTarget)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001918 {
kbr@google.com4ab3da02011-01-19 03:00:39 +00001919 ERR("Failed to retrieve the render target.");
1920 return error(GL_OUT_OF_MEMORY);
1921 }
1922
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001923 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE);
kbr@google.com4ab3da02011-01-19 03:00:39 +00001924
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001925 if (!mImageArray[level].isRenderableFormat())
kbr@google.com4ab3da02011-01-19 03:00:39 +00001926 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001927 mImageArray[level].copy(0, 0, x, y, width, height, renderTarget);
1928 mDirtyImages = true;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001929 }
zmo@google.com6a8e9d62010-09-02 17:54:23 +00001930 else
1931 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001932 if (!mTexStorage || !mTexStorage->isRenderTarget())
kbr@google.com4ab3da02011-01-19 03:00:39 +00001933 {
1934 convertToRenderTarget();
kbr@google.com4ab3da02011-01-19 03:00:39 +00001935 }
zmo@google.com86c3f272011-06-21 02:23:19 +00001936
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001937 mImageArray[level].markClean();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001938
kbr@google.com4ab3da02011-01-19 03:00:39 +00001939 if (width != 0 && height != 0 && level < levelCount())
1940 {
zmo@google.com86c3f272011-06-21 02:23:19 +00001941 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1942 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1943 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1944 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1945 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001946
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001947 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[level].getHeight());
zmo@google.com86c3f272011-06-21 02:23:19 +00001948
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001949 IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001950
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001951 if (dest)
1952 {
1953 getBlitter()->copy(renderTarget, sourceRect, format, 0, destYOffset, dest);
1954 dest->Release();
1955 }
kbr@google.com4ab3da02011-01-19 03:00:39 +00001956 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001957 }
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001958
1959 renderTarget->Release();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001960}
1961
zmo@google.com86c3f272011-06-21 02:23:19 +00001962void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001963{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001964 if (xoffset + width > mImageArray[level].getWidth() || yoffset + height > mImageArray[level].getHeight())
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001965 {
1966 return error(GL_INVALID_VALUE);
1967 }
1968
kbr@google.com4ab3da02011-01-19 03:00:39 +00001969 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1970
1971 if (!renderTarget)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001972 {
kbr@google.com4ab3da02011-01-19 03:00:39 +00001973 ERR("Failed to retrieve the render target.");
1974 return error(GL_OUT_OF_MEMORY);
1975 }
1976
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001977 if (!mImageArray[level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
kbr@google.com4ab3da02011-01-19 03:00:39 +00001978 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001979 mImageArray[level].copy(xoffset, yoffset, x, y, width, height, renderTarget);
1980 mDirtyImages = true;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001981 }
1982 else
1983 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001984 if (!mTexStorage || !mTexStorage->isRenderTarget())
kbr@google.com4ab3da02011-01-19 03:00:39 +00001985 {
1986 convertToRenderTarget();
kbr@google.com4ab3da02011-01-19 03:00:39 +00001987 }
zmo@google.com86c3f272011-06-21 02:23:19 +00001988
1989 updateTexture();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00001990
kbr@google.com4ab3da02011-01-19 03:00:39 +00001991 if (level < levelCount())
1992 {
zmo@google.com86c3f272011-06-21 02:23:19 +00001993 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1994 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1995 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1996 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1997 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1998
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00001999 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].getHeight());
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002000
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002001 IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002002
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002003 if (dest)
2004 {
2005 getBlitter()->copy(renderTarget, sourceRect, mImageArray[0].getFormat(), xoffset, destYOffset, dest);
2006 dest->Release();
2007 }
2008 }
2009 }
2010
2011 renderTarget->Release();
2012}
2013
2014void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
2015{
2016 GLenum format = gl::ExtractFormat(internalformat);
2017 GLenum type = gl::ExtractType(internalformat);
2018 D3DFORMAT d3dfmt = ConvertTextureFormatType(format, type);
2019 const bool renderTarget = IsTextureFormatRenderable(d3dfmt) && (mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2020
2021 delete mTexStorage;
2022 mTexStorage = new TextureStorage2D(levels, d3dfmt, width, height, renderTarget);
2023 mImmutable = true;
2024
2025 for (int level = 0; level < levels; level++)
2026 {
2027 mImageArray[level].redefine(format, width, height, type, true);
2028 width = std::max(1, width >> 1);
2029 height = std::max(1, height >> 1);
2030 }
2031
2032 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2033 {
2034 mImageArray[level].redefine(GL_NONE, 0, 0, GL_UNSIGNED_BYTE, true);
2035 }
2036
2037 if (mTexStorage->isManaged())
2038 {
2039 int levels = levelCount();
2040
2041 for (int level = 0; level < levels; level++)
2042 {
2043 IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level);
2044 mImageArray[level].setManagedSurface(surface);
kbr@google.com4ab3da02011-01-19 03:00:39 +00002045 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002046 }
2047}
2048
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002049// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
2050bool Texture2D::isSamplerComplete() const
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002051{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002052 GLsizei width = mImageArray[0].getWidth();
2053 GLsizei height = mImageArray[0].getHeight();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002054
2055 if (width <= 0 || height <= 0)
2056 {
2057 return false;
2058 }
2059
2060 bool mipmapping = false;
2061
2062 switch (mMinFilter)
2063 {
2064 case GL_NEAREST:
2065 case GL_LINEAR:
2066 mipmapping = false;
2067 break;
2068 case GL_NEAREST_MIPMAP_NEAREST:
2069 case GL_LINEAR_MIPMAP_NEAREST:
2070 case GL_NEAREST_MIPMAP_LINEAR:
2071 case GL_LINEAR_MIPMAP_LINEAR:
2072 mipmapping = true;
2073 break;
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002074 default: UNREACHABLE();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002075 }
2076
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002077 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) ||
2078 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsFloat16LinearFilter()))
kbr@google.com4ab3da02011-01-19 03:00:39 +00002079 {
2080 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
2081 {
2082 return false;
2083 }
2084 }
2085
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002086 bool npotSupport = getContext()->supportsNonPower2Texture();
kbr@google.com4ab3da02011-01-19 03:00:39 +00002087
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002088 if (!npotSupport)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002089 {
zmo@google.com86c3f272011-06-21 02:23:19 +00002090 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
2091 (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
2092 {
2093 return false;
2094 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002095 }
2096
2097 if (mipmapping)
2098 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002099 if (!npotSupport)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002100 {
zmo@google.com86c3f272011-06-21 02:23:19 +00002101 if (!isPow2(width) || !isPow2(height))
2102 {
2103 return false;
2104 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002105 }
2106
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002107 if (!isMipmapComplete())
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002108 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002109 return false;
2110 }
2111 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002112
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002113 return true;
2114}
zmo@google.com86c3f272011-06-21 02:23:19 +00002115
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002116// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
2117bool Texture2D::isMipmapComplete() const
2118{
2119 if (isImmutable())
2120 {
2121 return true;
2122 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002123
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002124 GLsizei width = mImageArray[0].getWidth();
2125 GLsizei height = mImageArray[0].getHeight();
2126
2127 if (width <= 0 || height <= 0)
2128 {
2129 return false;
2130 }
2131
2132 int q = log2(std::max(width, height));
2133
2134 for (int level = 1; level <= q; level++)
2135 {
2136 if (mImageArray[level].getFormat() != mImageArray[0].getFormat())
2137 {
2138 return false;
2139 }
2140
2141 if (mImageArray[level].getType() != mImageArray[0].getType())
2142 {
2143 return false;
2144 }
2145
2146 if (mImageArray[level].getWidth() != std::max(1, width >> level))
2147 {
2148 return false;
2149 }
2150
2151 if (mImageArray[level].getHeight() != std::max(1, height >> level))
2152 {
2153 return false;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002154 }
2155 }
2156
2157 return true;
2158}
2159
zmo@google.com6a8e9d62010-09-02 17:54:23 +00002160bool Texture2D::isCompressed() const
2161{
zmo@google.com86c3f272011-06-21 02:23:19 +00002162 return IsCompressed(getInternalFormat());
zmo@google.com6a8e9d62010-09-02 17:54:23 +00002163}
2164
zmo@google.com86c3f272011-06-21 02:23:19 +00002165IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002166{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002167 return mTexStorage ? mTexStorage->getBaseTexture() : NULL;
zmo@google.com86c3f272011-06-21 02:23:19 +00002168}
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002169
zmo@google.com86c3f272011-06-21 02:23:19 +00002170// Constructs a Direct3D 9 texture resource from the texture images
2171void Texture2D::createTexture()
2172{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002173 GLsizei width = mImageArray[0].getWidth();
2174 GLsizei height = mImageArray[0].getHeight();
2175 GLint levels = creationLevels(width, height);
zmo@google.com86c3f272011-06-21 02:23:19 +00002176 D3DFORMAT format = mImageArray[0].getD3DFormat();
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002177 const bool renderTarget = IsTextureFormatRenderable(format) && (mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002178
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002179 delete mTexStorage;
2180 mTexStorage = new TextureStorage2D(levels, format, width, height, renderTarget);
2181
2182 if (mTexStorage->isManaged())
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002183 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002184 int levels = levelCount();
2185
2186 for (int level = 0; level < levels; level++)
2187 {
2188 IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level);
2189 mImageArray[level].setManagedSurface(surface);
2190 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002191 }
2192
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002193 mDirtyImages = true;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002194}
2195
2196void Texture2D::updateTexture()
2197{
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002198 int levels = levelCount();
2199
2200 for (int level = 0; level < levels; level++)
2201 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002202 Image *image = &mImageArray[level];
2203
2204 if (image->isDirty())
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002205 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002206 commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight());
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002207 }
2208 }
2209}
2210
zmo@google.com86c3f272011-06-21 02:23:19 +00002211void Texture2D::convertToRenderTarget()
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002212{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002213 TextureStorage2D *newTexStorage = NULL;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002214
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002215 if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002216 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002217 GLsizei width = mImageArray[0].getWidth();
2218 GLsizei height = mImageArray[0].getHeight();
2219 GLint levels = creationLevels(width, height);
zmo@google.com86c3f272011-06-21 02:23:19 +00002220 D3DFORMAT format = mImageArray[0].getD3DFormat();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002221
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002222 newTexStorage = new TextureStorage2D(levels, format, width, height, true);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002223
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002224 if (mTexStorage != NULL)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002225 {
2226 int levels = levelCount();
2227 for (int i = 0; i < levels; i++)
2228 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002229 IDirect3DSurface9 *source = mTexStorage->getSurfaceLevel(i);
2230 IDirect3DSurface9 *dest = newTexStorage->getSurfaceLevel(i);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002231
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002232 if (!copyToRenderTarget(dest, source, mTexStorage->isManaged()))
2233 {
2234 delete newTexStorage;
2235 source->Release();
2236 dest->Release();
2237 return error(GL_OUT_OF_MEMORY);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002238 }
2239
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002240 if (source) source->Release();
2241 if (dest) dest->Release();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002242 }
2243 }
2244 }
2245
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002246 delete mTexStorage;
2247 mTexStorage = newTexStorage;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002248
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002249 mDirtyImages = true;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002250}
2251
2252void Texture2D::generateMipmaps()
2253{
zmo@google.com86c3f272011-06-21 02:23:19 +00002254 if (!getContext()->supportsNonPower2Texture())
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002255 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002256 if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight()))
zmo@google.com86c3f272011-06-21 02:23:19 +00002257 {
2258 return error(GL_INVALID_OPERATION);
2259 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002260 }
2261
2262 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002263 unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight()));
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002264 for (unsigned int i = 1; i <= q; i++)
2265 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002266 redefineImage(i, mImageArray[0].getFormat(),
2267 std::max(mImageArray[0].getWidth() >> i, 1),
2268 std::max(mImageArray[0].getHeight() >> i, 1),
2269 mImageArray[0].getType());
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002270 }
2271
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002272 if (mTexStorage && mTexStorage->isRenderTarget())
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002273 {
kbr@google.com4ab3da02011-01-19 03:00:39 +00002274 for (unsigned int i = 1; i <= q; i++)
2275 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002276 IDirect3DSurface9 *upper = mTexStorage->getSurfaceLevel(i - 1);
2277 IDirect3DSurface9 *lower = mTexStorage->getSurfaceLevel(i);
kbr@google.com4ab3da02011-01-19 03:00:39 +00002278
2279 if (upper != NULL && lower != NULL)
2280 {
2281 getBlitter()->boxFilter(upper, lower);
2282 }
2283
2284 if (upper != NULL) upper->Release();
2285 if (lower != NULL) lower->Release();
zmo@google.com86c3f272011-06-21 02:23:19 +00002286
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002287 mImageArray[i].markClean();
kbr@google.com4ab3da02011-01-19 03:00:39 +00002288 }
2289 }
2290 else
2291 {
2292 for (unsigned int i = 1; i <= q; i++)
2293 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002294 if (mImageArray[i].getSurface() == NULL)
kbr@google.com4ab3da02011-01-19 03:00:39 +00002295 {
2296 return error(GL_OUT_OF_MEMORY);
2297 }
2298
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002299 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].getSurface(), NULL, NULL, mImageArray[i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0)))
kbr@google.com4ab3da02011-01-19 03:00:39 +00002300 {
2301 ERR(" failed to load filter %d to %d.", i - 1, i);
2302 }
2303
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002304 mImageArray[i].markDirty();
kbr@google.com4ab3da02011-01-19 03:00:39 +00002305 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002306 }
2307}
2308
zmo@google.com86c3f272011-06-21 02:23:19 +00002309Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002310{
2311 if (target != GL_TEXTURE_2D)
2312 {
zmo@google.com6a8e9d62010-09-02 17:54:23 +00002313 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002314 }
2315
dino@apple.comc93dbb32012-03-27 19:19:18 +00002316 if (mColorbufferProxy == NULL)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002317 {
dino@apple.comc93dbb32012-03-27 19:19:18 +00002318 mColorbufferProxy = new Renderbuffer(id(), new RenderbufferTexture(this, target));
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002319 }
2320
dino@apple.comc93dbb32012-03-27 19:19:18 +00002321 return mColorbufferProxy;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002322}
2323
2324IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
2325{
2326 ASSERT(target == GL_TEXTURE_2D);
2327
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002328 // ensure the underlying texture is created
2329 if (getStorage(true) == NULL)
kbr@google.com4ab3da02011-01-19 03:00:39 +00002330 {
2331 return NULL;
2332 }
zmo@google.com86c3f272011-06-21 02:23:19 +00002333
2334 updateTexture();
kbr@google.com4ab3da02011-01-19 03:00:39 +00002335
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002336 return mTexStorage->getSurfaceLevel(0);
2337}
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002338
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002339TextureStorage *Texture2D::getStorage(bool renderTarget)
2340{
2341 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2342 {
2343 if (renderTarget)
2344 {
2345 convertToRenderTarget();
2346 }
2347 else
2348 {
2349 createTexture();
2350 }
2351 }
2352
2353 return mTexStorage;
2354}
2355
2356TextureStorageCubeMap::TextureStorageCubeMap(int levels, D3DFORMAT format, int size, bool renderTarget)
2357 : TextureStorage(renderTarget), mFirstRenderTargetSerial(RenderbufferStorage::issueCubeSerials())
2358{
2359 IDirect3DDevice9 *device = getDevice();
2360
2361 mTexture = NULL;
2362 HRESULT result = device->CreateCubeTexture(size, levels, isRenderTarget() ? D3DUSAGE_RENDERTARGET : 0, format, getPool(), &mTexture, NULL);
2363
2364 if (FAILED(result))
2365 {
2366 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2367 error(GL_OUT_OF_MEMORY);
2368 }
2369}
2370
2371TextureStorageCubeMap::~TextureStorageCubeMap()
2372{
2373 if (mTexture)
2374 {
2375 mTexture->Release();
2376 }
2377}
2378
2379IDirect3DSurface9 *TextureStorageCubeMap::getCubeMapSurface(GLenum faceTarget, int level)
2380{
2381 IDirect3DSurface9 *surface = NULL;
2382
2383 if (mTexture)
2384 {
2385 HRESULT result = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(faceTarget), level, &surface);
2386 ASSERT(SUCCEEDED(result));
2387 }
2388
2389 return surface;
2390}
2391
2392IDirect3DBaseTexture9 *TextureStorageCubeMap::getBaseTexture() const
2393{
2394 return mTexture;
2395}
2396
2397unsigned int TextureStorageCubeMap::getRenderTargetSerial(GLenum target) const
2398{
2399 return mFirstRenderTargetSerial + TextureCubeMap::faceIndex(target);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002400}
2401
zmo@google.com6a8e9d62010-09-02 17:54:23 +00002402TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002403{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002404 mTexStorage = NULL;
dino@apple.comc93dbb32012-03-27 19:19:18 +00002405 for (int i = 0; i < 6; i++)
2406 {
2407 mFaceProxies[i] = NULL;
2408 mFaceProxyRefs[i] = 0;
2409 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002410}
2411
2412TextureCubeMap::~TextureCubeMap()
2413{
2414 for (int i = 0; i < 6; i++)
2415 {
dino@apple.comc93dbb32012-03-27 19:19:18 +00002416 mFaceProxies[i] = NULL;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002417 }
2418
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002419 delete mTexStorage;
2420 mTexStorage = NULL;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002421}
2422
dino@apple.comc93dbb32012-03-27 19:19:18 +00002423// We need to maintain a count of references to renderbuffers acting as
2424// proxies for this texture, so that the texture is not deleted while
2425// proxy references still exist. If the reference count drops to zero,
2426// we set our proxy pointer NULL, so that a new attempt at referencing
2427// will cause recreation.
2428void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
2429{
2430 for (int i = 0; i < 6; i++)
2431 {
2432 if (mFaceProxies[i] == proxy)
2433 mFaceProxyRefs[i]++;
2434 }
2435}
2436
2437void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
2438{
2439 for (int i = 0; i < 6; i++)
2440 {
2441 if (mFaceProxies[i] == proxy)
2442 {
2443 if (mFaceProxyRefs[i] > 0)
2444 mFaceProxyRefs[i]--;
2445
2446 if (mFaceProxyRefs[i] == 0)
2447 mFaceProxies[i] = NULL;
2448 }
2449 }
2450}
2451
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002452GLenum TextureCubeMap::getTarget() const
2453{
2454 return GL_TEXTURE_CUBE_MAP;
2455}
2456
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002457GLsizei TextureCubeMap::getWidth(GLint level) const
zmo@google.com86c3f272011-06-21 02:23:19 +00002458{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002459 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2460 return mImageArray[0][level].getWidth();
2461 else
2462 return 0;
zmo@google.com86c3f272011-06-21 02:23:19 +00002463}
2464
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002465GLsizei TextureCubeMap::getHeight(GLint level) const
zmo@google.com86c3f272011-06-21 02:23:19 +00002466{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002467 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2468 return mImageArray[0][level].getHeight();
2469 else
2470 return 0;
zmo@google.com86c3f272011-06-21 02:23:19 +00002471}
2472
2473GLenum TextureCubeMap::getInternalFormat() const
zmo@google.com6a8e9d62010-09-02 17:54:23 +00002474{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002475 return mImageArray[0][0].getFormat();
zmo@google.com6a8e9d62010-09-02 17:54:23 +00002476}
2477
zmo@google.com86c3f272011-06-21 02:23:19 +00002478GLenum TextureCubeMap::getType() const
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002479{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002480 return mImageArray[0][0].getType();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002481}
2482
zmo@google.com86c3f272011-06-21 02:23:19 +00002483D3DFORMAT TextureCubeMap::getD3DFormat() const
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002484{
zmo@google.com86c3f272011-06-21 02:23:19 +00002485 return mImageArray[0][0].getD3DFormat();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002486}
2487
zmo@google.com86c3f272011-06-21 02:23:19 +00002488void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002489{
zmo@google.com86c3f272011-06-21 02:23:19 +00002490 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002491}
2492
zmo@google.com86c3f272011-06-21 02:23:19 +00002493void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002494{
zmo@google.com86c3f272011-06-21 02:23:19 +00002495 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002496}
2497
zmo@google.com86c3f272011-06-21 02:23:19 +00002498void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002499{
zmo@google.com86c3f272011-06-21 02:23:19 +00002500 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002501}
2502
zmo@google.com86c3f272011-06-21 02:23:19 +00002503void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002504{
zmo@google.com86c3f272011-06-21 02:23:19 +00002505 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002506}
2507
zmo@google.com86c3f272011-06-21 02:23:19 +00002508void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
zmo@google.com6a8e9d62010-09-02 17:54:23 +00002509{
zmo@google.com86c3f272011-06-21 02:23:19 +00002510 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
2511}
zmo@google.com6a8e9d62010-09-02 17:54:23 +00002512
zmo@google.com86c3f272011-06-21 02:23:19 +00002513void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2514{
2515 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
2516}
2517
2518void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
2519{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002520 redefineImage(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
zmo@google.com86c3f272011-06-21 02:23:19 +00002521
2522 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
zmo@google.com6a8e9d62010-09-02 17:54:23 +00002523}
2524
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002525void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002526{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002527 ASSERT(mImageArray[face][level].getSurface() != NULL);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002528
2529 if (level < levelCount())
2530 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002531 IDirect3DSurface9 *destLevel = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002532 ASSERT(destLevel != NULL);
2533
2534 if (destLevel != NULL)
2535 {
zmo@google.com86c3f272011-06-21 02:23:19 +00002536 Image *image = &mImageArray[face][level];
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002537 image->updateSurface(destLevel, xoffset, yoffset, width, height);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002538
2539 destLevel->Release();
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002540 image->markClean();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002541 }
2542 }
2543}
2544
kbr@google.com4ab3da02011-01-19 03:00:39 +00002545void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002546{
kbr@google.com4ab3da02011-01-19 03:00:39 +00002547 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
zmo@google.com6a8e9d62010-09-02 17:54:23 +00002548 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002549 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
zmo@google.com6a8e9d62010-09-02 17:54:23 +00002550 }
2551}
2552
kbr@google.com4ab3da02011-01-19 03:00:39 +00002553void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
zmo@google.com6a8e9d62010-09-02 17:54:23 +00002554{
kbr@google.com4ab3da02011-01-19 03:00:39 +00002555 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
zmo@google.com6a8e9d62010-09-02 17:54:23 +00002556 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002557 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
zmo@google.com6a8e9d62010-09-02 17:54:23 +00002558 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002559}
2560
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002561// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
2562bool TextureCubeMap::isSamplerComplete() const
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002563{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002564 int size = mImageArray[0][0].getWidth();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002565
2566 bool mipmapping;
2567
2568 switch (mMinFilter)
2569 {
2570 case GL_NEAREST:
2571 case GL_LINEAR:
2572 mipmapping = false;
2573 break;
2574 case GL_NEAREST_MIPMAP_NEAREST:
2575 case GL_LINEAR_MIPMAP_NEAREST:
2576 case GL_NEAREST_MIPMAP_LINEAR:
2577 case GL_LINEAR_MIPMAP_LINEAR:
2578 mipmapping = true;
2579 break;
dino@apple.comc93dbb32012-03-27 19:19:18 +00002580 default:
2581 UNREACHABLE();
2582 return false;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002583 }
2584
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002585 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) ||
2586 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsFloat16LinearFilter()))
kbr@google.com4ab3da02011-01-19 03:00:39 +00002587 {
2588 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
2589 {
2590 return false;
2591 }
2592 }
2593
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002594 if (!isPow2(size) && !getContext()->supportsNonPower2Texture())
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002595 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002596 if (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE || mipmapping)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002597 {
2598 return false;
2599 }
zmo@google.com86c3f272011-06-21 02:23:19 +00002600 }
2601
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002602 if (!mipmapping)
zmo@google.com86c3f272011-06-21 02:23:19 +00002603 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002604 if (!isCubeComplete())
zmo@google.com86c3f272011-06-21 02:23:19 +00002605 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002606 return false;
2607 }
2608 }
2609 else
2610 {
2611 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
2612 {
2613 return false;
2614 }
2615 }
2616
2617 return true;
2618}
2619
2620// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
2621bool TextureCubeMap::isCubeComplete() const
2622{
2623 if (mImageArray[0][0].getWidth() <= 0 || mImageArray[0][0].getHeight() != mImageArray[0][0].getWidth())
2624 {
2625 return false;
2626 }
2627
2628 for (unsigned int face = 1; face < 6; face++)
2629 {
2630 if (mImageArray[face][0].getWidth() != mImageArray[0][0].getWidth() ||
2631 mImageArray[face][0].getWidth() != mImageArray[0][0].getHeight() ||
2632 mImageArray[face][0].getFormat() != mImageArray[0][0].getFormat() ||
2633 mImageArray[face][0].getType() != mImageArray[0][0].getType())
2634 {
2635 return false;
2636 }
2637 }
2638
2639 return true;
2640}
2641
2642bool TextureCubeMap::isMipmapCubeComplete() const
2643{
2644 if (isImmutable())
2645 {
2646 return true;
2647 }
2648
2649 if (!isCubeComplete())
2650 {
2651 return false;
2652 }
2653
2654 GLsizei size = mImageArray[0][0].getWidth();
2655
2656 int q = log2(size);
2657
2658 for (int face = 0; face < 6; face++)
2659 {
2660 for (int level = 1; level <= q; level++)
2661 {
2662 if (mImageArray[face][level].getFormat() != mImageArray[0][0].getFormat())
zmo@google.com86c3f272011-06-21 02:23:19 +00002663 {
2664 return false;
2665 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002666
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002667 if (mImageArray[face][level].getType() != mImageArray[0][0].getType())
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002668 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002669 return false;
2670 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002671
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002672 if (mImageArray[face][level].getWidth() != std::max(1, size >> level))
2673 {
2674 return false;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002675 }
2676 }
2677 }
2678
2679 return true;
2680}
2681
zmo@google.com6a8e9d62010-09-02 17:54:23 +00002682bool TextureCubeMap::isCompressed() const
2683{
zmo@google.com86c3f272011-06-21 02:23:19 +00002684 return IsCompressed(getInternalFormat());
2685}
2686
2687IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
2688{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002689 return mTexStorage ? mTexStorage->getBaseTexture() : NULL;
zmo@google.com6a8e9d62010-09-02 17:54:23 +00002690}
2691
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002692// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
zmo@google.com86c3f272011-06-21 02:23:19 +00002693void TextureCubeMap::createTexture()
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002694{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002695 GLsizei size = mImageArray[0][0].getWidth();
2696 GLint levels = creationLevels(size, 0);
zmo@google.com86c3f272011-06-21 02:23:19 +00002697 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002698 const bool renderTarget = IsTextureFormatRenderable(format) && (mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002699
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002700 delete mTexStorage;
2701 mTexStorage = new TextureStorageCubeMap(levels, format, size, renderTarget);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002702
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002703 if (mTexStorage->isManaged())
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002704 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002705 int levels = levelCount();
2706
2707 for (int face = 0; face < 6; face++)
2708 {
2709 for (int level = 0; level < levels; level++)
2710 {
2711 IDirect3DSurface9 *surface = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2712 mImageArray[face][level].setManagedSurface(surface);
2713 }
2714 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002715 }
2716
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002717 mDirtyImages = true;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002718}
2719
2720void TextureCubeMap::updateTexture()
2721{
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002722 for (int face = 0; face < 6; face++)
2723 {
2724 int levels = levelCount();
2725 for (int level = 0; level < levels; level++)
2726 {
zmo@google.com86c3f272011-06-21 02:23:19 +00002727 Image *image = &mImageArray[face][level];
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002728
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002729 if (image->isDirty())
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002730 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002731 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002732 }
2733 }
2734 }
2735}
2736
zmo@google.com86c3f272011-06-21 02:23:19 +00002737void TextureCubeMap::convertToRenderTarget()
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002738{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002739 TextureStorageCubeMap *newTexStorage = NULL;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002740
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002741 if (mImageArray[0][0].getWidth() != 0)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002742 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002743 GLsizei size = mImageArray[0][0].getWidth();
2744 GLint levels = creationLevels(size, 0);
zmo@google.com86c3f272011-06-21 02:23:19 +00002745 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002746
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002747 newTexStorage = new TextureStorageCubeMap(levels, format, size, true);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002748
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002749 if (mTexStorage != NULL)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002750 {
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002751 int levels = levelCount();
2752 for (int f = 0; f < 6; f++)
2753 {
2754 for (int i = 0; i < levels; i++)
2755 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002756 IDirect3DSurface9 *source = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2757 IDirect3DSurface9 *dest = newTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002758
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002759 if (!copyToRenderTarget(dest, source, mTexStorage->isManaged()))
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002760 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002761 delete newTexStorage;
2762 source->Release();
2763 dest->Release();
2764 return error(GL_OUT_OF_MEMORY);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002765 }
2766
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002767 if (source) source->Release();
2768 if (dest) dest->Release();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002769 }
2770 }
2771 }
2772 }
2773
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002774 delete mTexStorage;
2775 mTexStorage = newTexStorage;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002776
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002777 mDirtyImages = true;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002778}
2779
zmo@google.com86c3f272011-06-21 02:23:19 +00002780void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002781{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002782 redefineImage(faceIndex, level, format, width, height, type);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002783
zmo@google.com86c3f272011-06-21 02:23:19 +00002784 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002785}
2786
2787unsigned int TextureCubeMap::faceIndex(GLenum face)
2788{
2789 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2790 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2791 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2792 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2793 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2794
2795 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2796}
2797
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002798void TextureCubeMap::redefineImage(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002799{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002800 bool redefined = mImageArray[face][level].redefine(format, width, height, type, false);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002801
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002802 if (mTexStorage && redefined)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002803 {
kbr@google.com4ab3da02011-01-19 03:00:39 +00002804 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002805 {
2806 for (int f = 0; f < 6; f++)
2807 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002808 mImageArray[f][i].markDirty();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002809 }
2810 }
2811
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002812 delete mTexStorage;
2813 mTexStorage = NULL;
2814
2815 mDirtyImages = true;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002816 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002817}
2818
zmo@google.com86c3f272011-06-21 02:23:19 +00002819void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002820{
kbr@google.com4ab3da02011-01-19 03:00:39 +00002821 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002822
kbr@google.com4ab3da02011-01-19 03:00:39 +00002823 if (!renderTarget)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002824 {
kbr@google.com4ab3da02011-01-19 03:00:39 +00002825 ERR("Failed to retrieve the render target.");
2826 return error(GL_OUT_OF_MEMORY);
2827 }
2828
2829 unsigned int faceindex = faceIndex(target);
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002830 redefineImage(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
kbr@google.com4ab3da02011-01-19 03:00:39 +00002831
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002832 if (!mImageArray[faceindex][level].isRenderableFormat())
kbr@google.com4ab3da02011-01-19 03:00:39 +00002833 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002834 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
2835 mDirtyImages = true;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002836 }
zmo@google.com6a8e9d62010-09-02 17:54:23 +00002837 else
2838 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002839 if (!mTexStorage || !mTexStorage->isRenderTarget())
kbr@google.com4ab3da02011-01-19 03:00:39 +00002840 {
2841 convertToRenderTarget();
kbr@google.com4ab3da02011-01-19 03:00:39 +00002842 }
zmo@google.com86c3f272011-06-21 02:23:19 +00002843
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002844 mImageArray[faceindex][level].markClean();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002845
kbr@google.com4ab3da02011-01-19 03:00:39 +00002846 ASSERT(width == height);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002847
kbr@google.com4ab3da02011-01-19 03:00:39 +00002848 if (width > 0 && level < levelCount())
2849 {
zmo@google.com86c3f272011-06-21 02:23:19 +00002850 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2851 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2852 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2853 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2854 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2855
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002856 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[faceindex][level].getWidth());
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002857
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002858 IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002859
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002860 if (dest)
2861 {
2862 getBlitter()->copy(renderTarget, sourceRect, format, 0, destYOffset, dest);
2863 dest->Release();
2864 }
kbr@google.com4ab3da02011-01-19 03:00:39 +00002865 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002866 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002867
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002868 renderTarget->Release();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002869}
2870
zmo@google.com86c3f272011-06-21 02:23:19 +00002871void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002872{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002873 GLsizei size = mImageArray[faceIndex(target)][level].getWidth();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002874
2875 if (xoffset + width > size || yoffset + height > size)
2876 {
2877 return error(GL_INVALID_VALUE);
2878 }
2879
kbr@google.com4ab3da02011-01-19 03:00:39 +00002880 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2881
2882 if (!renderTarget)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002883 {
kbr@google.com4ab3da02011-01-19 03:00:39 +00002884 ERR("Failed to retrieve the render target.");
2885 return error(GL_OUT_OF_MEMORY);
2886 }
2887
2888 unsigned int faceindex = faceIndex(target);
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002889
2890 if (!mImageArray[faceindex][level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
kbr@google.com4ab3da02011-01-19 03:00:39 +00002891 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002892 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
2893 mDirtyImages = true;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002894 }
2895 else
2896 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002897 if (!mTexStorage || !mTexStorage->isRenderTarget())
kbr@google.com4ab3da02011-01-19 03:00:39 +00002898 {
2899 convertToRenderTarget();
kbr@google.com4ab3da02011-01-19 03:00:39 +00002900 }
zmo@google.com86c3f272011-06-21 02:23:19 +00002901
2902 updateTexture();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002903
kbr@google.com4ab3da02011-01-19 03:00:39 +00002904 if (level < levelCount())
2905 {
zmo@google.com86c3f272011-06-21 02:23:19 +00002906 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2907 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2908 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2909 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2910 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2911
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002912 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].getWidth());
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002913
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002914 IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002915
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002916 if (dest)
2917 {
2918 getBlitter()->copy(renderTarget, sourceRect, mImageArray[0][0].getFormat(), xoffset, destYOffset, dest);
2919 dest->Release();
2920 }
kbr@google.com4ab3da02011-01-19 03:00:39 +00002921 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002922 }
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002923
2924 renderTarget->Release();
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002925}
2926
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002927void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002928{
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002929 GLenum format = gl::ExtractFormat(internalformat);
2930 GLenum type = gl::ExtractType(internalformat);
2931 D3DFORMAT d3dfmt = ConvertTextureFormatType(format, type);
2932 const bool renderTarget = IsTextureFormatRenderable(d3dfmt) && (mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002933
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002934 delete mTexStorage;
2935 mTexStorage = new TextureStorageCubeMap(levels, d3dfmt, size, renderTarget);
2936 mImmutable = true;
2937
2938 for (int level = 0; level < levels; level++)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002939 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002940 for (int face = 0; face < 6; face++)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002941 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002942 mImageArray[face][level].redefine(format, size, size, type, true);
2943 size = std::max(1, size >> 1);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002944 }
2945 }
2946
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002947 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2948 {
2949 for (int face = 0; face < 6; face++)
2950 {
2951 mImageArray[face][level].redefine(GL_NONE, 0, 0, GL_UNSIGNED_BYTE, true);
2952 }
2953 }
2954
2955 if (mTexStorage->isManaged())
2956 {
2957 int levels = levelCount();
2958
2959 for (int face = 0; face < 6; face++)
2960 {
2961 for (int level = 0; level < levels; level++)
2962 {
2963 IDirect3DSurface9 *surface = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2964 mImageArray[face][level].setManagedSurface(surface);
2965 }
2966 }
2967 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002968}
2969
2970void TextureCubeMap::generateMipmaps()
2971{
zmo@google.com86c3f272011-06-21 02:23:19 +00002972 if (!isCubeComplete())
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002973 {
2974 return error(GL_INVALID_OPERATION);
2975 }
2976
zmo@google.com86c3f272011-06-21 02:23:19 +00002977 if (!getContext()->supportsNonPower2Texture())
2978 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002979 if (!isPow2(mImageArray[0][0].getWidth()))
zmo@google.com86c3f272011-06-21 02:23:19 +00002980 {
2981 return error(GL_INVALID_OPERATION);
2982 }
2983 }
2984
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002985 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002986 unsigned int q = log2(mImageArray[0][0].getWidth());
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002987 for (unsigned int f = 0; f < 6; f++)
2988 {
2989 for (unsigned int i = 1; i <= q; i++)
2990 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002991 redefineImage(f, i, mImageArray[f][0].getFormat(),
2992 std::max(mImageArray[f][0].getWidth() >> i, 1),
2993 std::max(mImageArray[f][0].getWidth() >> i, 1),
2994 mImageArray[f][0].getType());
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002995 }
2996 }
2997
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00002998 if (mTexStorage && mTexStorage->isRenderTarget())
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00002999 {
kbr@google.com4ab3da02011-01-19 03:00:39 +00003000 for (unsigned int f = 0; f < 6; f++)
3001 {
3002 for (unsigned int i = 1; i <= q; i++)
3003 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00003004 IDirect3DSurface9 *upper = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
3005 IDirect3DSurface9 *lower = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
kbr@google.com4ab3da02011-01-19 03:00:39 +00003006
3007 if (upper != NULL && lower != NULL)
3008 {
3009 getBlitter()->boxFilter(upper, lower);
3010 }
3011
3012 if (upper != NULL) upper->Release();
3013 if (lower != NULL) lower->Release();
zmo@google.com86c3f272011-06-21 02:23:19 +00003014
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00003015 mImageArray[f][i].markClean();
kbr@google.com4ab3da02011-01-19 03:00:39 +00003016 }
3017 }
3018 }
3019 else
3020 {
3021 for (unsigned int f = 0; f < 6; f++)
3022 {
3023 for (unsigned int i = 1; i <= q; i++)
3024 {
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00003025 if (mImageArray[f][i].getSurface() == NULL)
kbr@google.com4ab3da02011-01-19 03:00:39 +00003026 {
3027 return error(GL_OUT_OF_MEMORY);
3028 }
3029
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00003030 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].getSurface(), NULL, NULL, mImageArray[f][i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0)))
kbr@google.com4ab3da02011-01-19 03:00:39 +00003031 {
3032 ERR(" failed to load filter %d to %d.", i - 1, i);
3033 }
3034
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00003035 mImageArray[f][i].markDirty();
kbr@google.com4ab3da02011-01-19 03:00:39 +00003036 }
3037 }
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00003038 }
3039}
3040
zmo@google.com86c3f272011-06-21 02:23:19 +00003041Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00003042{
3043 if (!IsCubemapTextureTarget(target))
3044 {
zmo@google.com6a8e9d62010-09-02 17:54:23 +00003045 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00003046 }
3047
3048 unsigned int face = faceIndex(target);
3049
dino@apple.comc93dbb32012-03-27 19:19:18 +00003050 if (mFaceProxies[face] == NULL)
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00003051 {
dino@apple.comc93dbb32012-03-27 19:19:18 +00003052 mFaceProxies[face] = new Renderbuffer(id(), new RenderbufferTexture(this, target));
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00003053 }
3054
dino@apple.comc93dbb32012-03-27 19:19:18 +00003055 return mFaceProxies[face];
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00003056}
3057
3058IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
3059{
3060 ASSERT(IsCubemapTextureTarget(target));
3061
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00003062 // ensure the underlying texture is created
3063 if (getStorage(true) == NULL)
kbr@google.com4ab3da02011-01-19 03:00:39 +00003064 {
3065 return NULL;
3066 }
zmo@google.com86c3f272011-06-21 02:23:19 +00003067
3068 updateTexture();
kbr@google.com4ab3da02011-01-19 03:00:39 +00003069
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00003070 return mTexStorage->getCubeMapSurface(target, 0);
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00003071}
3072
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00003073TextureStorage *TextureCubeMap::getStorage(bool renderTarget)
3074{
3075 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
3076 {
3077 if (renderTarget)
3078 {
3079 convertToRenderTarget();
3080 }
3081 else
3082 {
3083 createTexture();
3084 }
3085 }
3086
3087 return mTexStorage;
cmarrin@apple.comf0c26ac2010-08-03 16:26:48 +00003088}
cmarrin@apple.com128a99d2012-01-07 01:40:13 +00003089
3090}