blob: f66f572af5dfa7d7f85ec43682294e012377ad20 [file] [log] [blame]
daniel@transgaming.com4ba24062012-12-20 20:54:24 +00001//
2// Copyright (c) 2002-2012 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// Image9.cpp: Implements the rx::Image9 class, which acts as the interface to
8// the actual underlying surfaces of a Texture.
9
10#include "libGLESv2/renderer/Image9.h"
11
12#include "libEGL/Display.h"
13
14#include "libGLESv2/main.h"
15#include "libGLESv2/mathutil.h"
16#include "libGLESv2/utilities.h"
17#include "libGLESv2/Texture.h"
18#include "libGLESv2/Framebuffer.h"
19#include "libGLESv2/renderer/RenderTarget9.h"
daniel@transgaming.com34da3972012-12-20 21:10:29 +000020#include "libGLESv2/renderer/TextureStorage9.h"
daniel@transgaming.com4ba24062012-12-20 20:54:24 +000021
22#include "libGLESv2/renderer/renderer9_utils.h"
daniel@transgaming.com12e02212012-12-20 20:55:15 +000023#include "libGLESv2/renderer/generatemip.h"
daniel@transgaming.com4ba24062012-12-20 20:54:24 +000024
25namespace rx
26{
27
daniel@transgaming.com12e02212012-12-20 20:55:15 +000028Image9::Image9()
daniel@transgaming.com4ba24062012-12-20 20:54:24 +000029{
daniel@transgaming.com12e02212012-12-20 20:55:15 +000030 mSurface = NULL;
31 mRenderer = NULL;
32
33 mD3DPool = D3DPOOL_SYSTEMMEM;
34 mD3DFormat = D3DFMT_UNKNOWN;
35}
36
37Image9::~Image9()
daniel@transgaming.com4ba24062012-12-20 20:54:24 +000038{
daniel@transgaming.com12e02212012-12-20 20:55:15 +000039 if (mSurface)
daniel@transgaming.com4ba24062012-12-20 20:54:24 +000040 {
daniel@transgaming.com12e02212012-12-20 20:55:15 +000041 mSurface->Release();
daniel@transgaming.com4ba24062012-12-20 20:54:24 +000042 }
43}
44
daniel@transgaming.com12e02212012-12-20 20:55:15 +000045void Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface)
daniel@transgaming.com4ba24062012-12-20 20:54:24 +000046{
47 D3DSURFACE_DESC destDesc;
48 HRESULT result = destSurface->GetDesc(&destDesc);
49 ASSERT(SUCCEEDED(result));
50
51 D3DSURFACE_DESC sourceDesc;
52 result = sourceSurface->GetDesc(&sourceDesc);
53 ASSERT(SUCCEEDED(result));
54
55 ASSERT(sourceDesc.Format == destDesc.Format);
56 ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width);
57 ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height);
58
59 D3DLOCKED_RECT sourceLocked = {0};
60 result = sourceSurface->LockRect(&sourceLocked, NULL, D3DLOCK_READONLY);
61 ASSERT(SUCCEEDED(result));
62
63 D3DLOCKED_RECT destLocked = {0};
64 result = destSurface->LockRect(&destLocked, NULL, 0);
65 ASSERT(SUCCEEDED(result));
66
67 const unsigned char *sourceData = reinterpret_cast<const unsigned char*>(sourceLocked.pBits);
68 unsigned char *destData = reinterpret_cast<unsigned char*>(destLocked.pBits);
69
70 if (sourceData && destData)
71 {
72 switch (sourceDesc.Format)
73 {
74 case D3DFMT_L8:
75 GenerateMip<L8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
76 break;
77 case D3DFMT_A8L8:
78 GenerateMip<A8L8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
79 break;
80 case D3DFMT_A8R8G8B8:
81 case D3DFMT_X8R8G8B8:
82 GenerateMip<A8R8G8B8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
83 break;
84 case D3DFMT_A16B16G16R16F:
85 GenerateMip<A16B16G16R16F>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
86 break;
87 case D3DFMT_A32B32G32R32F:
88 GenerateMip<A32B32G32R32F>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
89 break;
90 default:
91 UNREACHABLE();
92 break;
93 }
94
95 destSurface->UnlockRect();
96 sourceSurface->UnlockRect();
97 }
98}
daniel@transgaming.com4ba24062012-12-20 20:54:24 +000099
100Image9 *Image9::makeImage9(Image *img)
101{
102 ASSERT(dynamic_cast<rx::Image9*>(img) != NULL);
103 return static_cast<rx::Image9*>(img);
104}
105
106void Image9::generateMipmap(Image9 *dest, Image9 *source)
107{
108 IDirect3DSurface9 *sourceSurface = source->getSurface();
109 if (sourceSurface == NULL)
110 return error(GL_OUT_OF_MEMORY);
111
112 IDirect3DSurface9 *destSurface = dest->getSurface();
daniel@transgaming.com12e02212012-12-20 20:55:15 +0000113 generateMip(destSurface, sourceSurface);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000114
daniel@transgaming.com5dd45022013-01-11 04:08:53 +0000115 dest->markDirty();
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000116}
117
118void Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source)
119{
120 D3DLOCKED_RECT sourceLock = {0};
121 D3DLOCKED_RECT destLock = {0};
122
123 source->LockRect(&sourceLock, NULL, 0);
124 dest->LockRect(&destLock, NULL, 0);
125
126 if (sourceLock.pBits && destLock.pBits)
127 {
128 D3DSURFACE_DESC desc;
129 source->GetDesc(&desc);
130
daniel@transgaming.com9a583652012-12-20 21:07:54 +0000131 int rows = d3d9::IsCompressedFormat(desc.Format) ? desc.Height / 4 : desc.Height;
132 int bytes = d3d9::ComputeRowSize(desc.Format, desc.Width);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000133 ASSERT(bytes <= sourceLock.Pitch && bytes <= destLock.Pitch);
134
135 for(int i = 0; i < rows; i++)
136 {
137 memcpy((char*)destLock.pBits + destLock.Pitch * i, (char*)sourceLock.pBits + sourceLock.Pitch * i, bytes);
138 }
139
140 source->UnlockRect();
141 dest->UnlockRect();
142 }
143 else UNREACHABLE();
144}
145
146bool Image9::redefine(rx::Renderer *renderer, GLint internalformat, GLsizei width, GLsizei height, bool forceRelease)
147{
148 if (mWidth != width ||
149 mHeight != height ||
150 mInternalFormat != internalformat ||
151 forceRelease)
152 {
153 mRenderer = Renderer9::makeRenderer9(renderer);
154
155 mWidth = width;
156 mHeight = height;
157 mInternalFormat = internalformat;
158 // compute the d3d format that will be used
159 mD3DFormat = mRenderer->ConvertTextureInternalFormat(internalformat);
160 mActualFormat = d3d9_gl::GetEquivalentFormat(mD3DFormat);
161
162 if (mSurface)
163 {
164 mSurface->Release();
165 mSurface = NULL;
166 }
167
168 return true;
169 }
170
171 return false;
172}
173
174void Image9::createSurface()
175{
176 if(mSurface)
177 {
178 return;
179 }
180
181 IDirect3DTexture9 *newTexture = NULL;
182 IDirect3DSurface9 *newSurface = NULL;
183 const D3DPOOL poolToUse = D3DPOOL_SYSTEMMEM;
184 const D3DFORMAT d3dFormat = getD3DFormat();
185 ASSERT(d3dFormat != D3DFMT_INTZ); // We should never get here for depth textures
186
187 if (mWidth != 0 && mHeight != 0)
188 {
189 int levelToFetch = 0;
190 GLsizei requestWidth = mWidth;
191 GLsizei requestHeight = mHeight;
192 gl::MakeValidSize(true, gl::IsCompressed(mInternalFormat), &requestWidth, &requestHeight, &levelToFetch);
193
daniel@transgaming.com204677a2013-01-11 21:16:09 +0000194 IDirect3DDevice9 *device = mRenderer->getDevice();
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000195
196 HRESULT result = device->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, 0, d3dFormat,
197 poolToUse, &newTexture, NULL);
198
199 if (FAILED(result))
200 {
201 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
202 ERR("Creating image surface failed.");
203 return error(GL_OUT_OF_MEMORY);
204 }
205
206 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
207 newTexture->Release();
208 }
209
210 mSurface = newSurface;
211 mDirty = false;
212 mD3DPool = poolToUse;
213}
214
215HRESULT Image9::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect)
216{
217 createSurface();
218
219 HRESULT result = D3DERR_INVALIDCALL;
220
221 if (mSurface)
222 {
223 result = mSurface->LockRect(lockedRect, rect, 0);
224 ASSERT(SUCCEEDED(result));
225
226 mDirty = true;
227 }
228
229 return result;
230}
231
232void Image9::unlock()
233{
234 if (mSurface)
235 {
236 HRESULT result = mSurface->UnlockRect();
237 ASSERT(SUCCEEDED(result));
238 }
239}
240
241bool Image9::isRenderableFormat() const
242{
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000243 return TextureStorage9::IsTextureFormatRenderable(getD3DFormat());
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000244}
245
246D3DFORMAT Image9::getD3DFormat() const
247{
248 // this should only happen if the image hasn't been redefined first
249 // which would be a bug by the caller
250 ASSERT(mD3DFormat != D3DFMT_UNKNOWN);
251
252 return mD3DFormat;
253}
254
255IDirect3DSurface9 *Image9::getSurface()
256{
257 createSurface();
258
259 return mSurface;
260}
261
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000262void Image9::setManagedSurface(TextureStorageInterface2D *storage, int level)
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000263{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000264 TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage->getStorageInstance());
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000265 setManagedSurface(storage9->getSurfaceLevel(level, false));
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000266}
267
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000268void Image9::setManagedSurface(TextureStorageInterfaceCube *storage, int face, int level)
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000269{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000270 TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage->getStorageInstance());
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000271 setManagedSurface(storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false));
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000272}
273
274void Image9::setManagedSurface(IDirect3DSurface9 *surface)
275{
276 D3DSURFACE_DESC desc;
277 surface->GetDesc(&desc);
278 ASSERT(desc.Pool == D3DPOOL_MANAGED);
279
280 if ((GLsizei)desc.Width == mWidth && (GLsizei)desc.Height == mHeight)
281 {
282 if (mSurface)
283 {
284 copyLockableSurfaces(surface, mSurface);
285 mSurface->Release();
286 }
287
288 mSurface = surface;
289 mD3DPool = desc.Pool;
290 }
291}
292
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000293bool Image9::updateSurface(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000294{
295 ASSERT(getSurface() != NULL);
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000296 TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage->getStorageInstance());
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000297 return updateSurface(storage9->getSurfaceLevel(level, true), xoffset, yoffset, width, height);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000298}
299
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000300bool Image9::updateSurface(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000301{
302 ASSERT(getSurface() != NULL);
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000303 TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage->getStorageInstance());
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000304 return updateSurface(storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true), xoffset, yoffset, width, height);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000305}
306
307bool Image9::updateSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
308{
309 if (!destSurface)
310 return false;
311
312 IDirect3DSurface9 *sourceSurface = getSurface();
313
314 if (sourceSurface && sourceSurface != destSurface)
315 {
316 RECT rect;
317 rect.left = xoffset;
318 rect.top = yoffset;
319 rect.right = xoffset + width;
320 rect.bottom = yoffset + height;
321
322 POINT point = {rect.left, rect.top};
323
daniel@transgaming.com204677a2013-01-11 21:16:09 +0000324 IDirect3DDevice9 *device = mRenderer->getDevice();
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000325
326 if (mD3DPool == D3DPOOL_MANAGED)
327 {
328 D3DSURFACE_DESC desc;
329 sourceSurface->GetDesc(&desc);
330
331 IDirect3DSurface9 *surf = 0;
332 HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL);
333
334 if (SUCCEEDED(result))
335 {
336 copyLockableSurfaces(surf, sourceSurface);
337 result = device->UpdateSurface(surf, &rect, destSurface, &point);
338 ASSERT(SUCCEEDED(result));
339 surf->Release();
340 }
341 }
342 else
343 {
344 // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools
345 HRESULT result = device->UpdateSurface(sourceSurface, &rect, destSurface, &point);
346 ASSERT(SUCCEEDED(result));
347 }
348 }
349
350 destSurface->Release();
351 return true;
352}
353
354// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
355// into the target pixel rectangle.
356void Image9::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
357 GLint unpackAlignment, const void *input)
358{
359 RECT lockRect =
360 {
361 xoffset, yoffset,
362 xoffset + width, yoffset + height
363 };
364
365 D3DLOCKED_RECT locked;
366 HRESULT result = lock(&locked, &lockRect);
367 if (FAILED(result))
368 {
369 return;
370 }
371
372
373 GLsizei inputPitch = gl::ComputePitch(width, mInternalFormat, unpackAlignment);
374
375 switch (mInternalFormat)
376 {
377 case GL_ALPHA8_EXT:
378 if (gl::supportsSSE2())
379 {
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000380 loadAlphaDataToBGRASSE2(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000381 }
382 else
383 {
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000384 loadAlphaDataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000385 }
386 break;
387 case GL_LUMINANCE8_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000388 loadLuminanceDataToNativeOrBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits, getD3DFormat() == D3DFMT_L8);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000389 break;
390 case GL_ALPHA32F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000391 loadAlphaFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000392 break;
393 case GL_LUMINANCE32F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000394 loadLuminanceFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000395 break;
396 case GL_ALPHA16F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000397 loadAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000398 break;
399 case GL_LUMINANCE16F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000400 loadLuminanceHalfFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000401 break;
402 case GL_LUMINANCE8_ALPHA8_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000403 loadLuminanceAlphaDataToNativeOrBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits, getD3DFormat() == D3DFMT_A8L8);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000404 break;
405 case GL_LUMINANCE_ALPHA32F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000406 loadLuminanceAlphaFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000407 break;
408 case GL_LUMINANCE_ALPHA16F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000409 loadLuminanceAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000410 break;
411 case GL_RGB8_OES:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000412 loadRGBUByteDataToBGRX(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000413 break;
414 case GL_RGB565:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000415 loadRGB565DataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000416 break;
417 case GL_RGBA8_OES:
418 if (gl::supportsSSE2())
419 {
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000420 loadRGBAUByteDataToBGRASSE2(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000421 }
422 else
423 {
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000424 loadRGBAUByteDataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000425 }
426 break;
427 case GL_RGBA4:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000428 loadRGBA4444DataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000429 break;
430 case GL_RGB5_A1:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000431 loadRGBA5551DataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000432 break;
433 case GL_BGRA8_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000434 loadBGRADataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000435 break;
436 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
437 case GL_RGB32F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000438 loadRGBFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000439 break;
440 case GL_RGB16F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000441 loadRGBHalfFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000442 break;
443 case GL_RGBA32F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000444 loadRGBAFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000445 break;
446 case GL_RGBA16F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000447 loadRGBAHalfFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000448 break;
449 default: UNREACHABLE();
450 }
451
452 unlock();
453}
454
455void Image9::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
456 const void *input)
457{
458 ASSERT(xoffset % 4 == 0);
459 ASSERT(yoffset % 4 == 0);
460
461 RECT lockRect = {
462 xoffset, yoffset,
463 xoffset + width, yoffset + height
464 };
465
466 D3DLOCKED_RECT locked;
467 HRESULT result = lock(&locked, &lockRect);
468 if (FAILED(result))
469 {
470 return;
471 }
472
473 GLsizei inputSize = gl::ComputeCompressedSize(width, height, mInternalFormat);
474 GLsizei inputPitch = gl::ComputeCompressedPitch(width, mInternalFormat);
475 int rows = inputSize / inputPitch;
476 for (int i = 0; i < rows; ++i)
477 {
478 memcpy((void*)((BYTE*)locked.pBits + i * locked.Pitch), (void*)((BYTE*)input + i * inputPitch), inputPitch);
479 }
480
481 unlock();
482}
483
484// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
485void Image9::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
486{
487 RenderTarget9 *renderTarget = NULL;
488 IDirect3DSurface9 *surface = NULL;
489 gl::Renderbuffer *colorbuffer = source->getColorbuffer();
490
491 if (colorbuffer)
492 {
493 renderTarget = RenderTarget9::makeRenderTarget9(colorbuffer->getRenderTarget());
494 }
495
496 if (renderTarget)
497 {
498 surface = renderTarget->getSurface();
499 }
500
501 if (!surface)
502 {
503 ERR("Failed to retrieve the render target.");
504 return error(GL_OUT_OF_MEMORY);
505 }
506
daniel@transgaming.com204677a2013-01-11 21:16:09 +0000507 IDirect3DDevice9 *device = mRenderer->getDevice();
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000508
509 IDirect3DSurface9 *renderTargetData = NULL;
510 D3DSURFACE_DESC description;
511 surface->GetDesc(&description);
512
513 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
514
515 if (FAILED(result))
516 {
517 ERR("Could not create matching destination surface.");
518 surface->Release();
519 return error(GL_OUT_OF_MEMORY);
520 }
521
522 result = device->GetRenderTargetData(surface, renderTargetData);
523
524 if (FAILED(result))
525 {
526 ERR("GetRenderTargetData unexpectedly failed.");
527 renderTargetData->Release();
528 surface->Release();
529 return error(GL_OUT_OF_MEMORY);
530 }
531
532 RECT sourceRect = {x, y, x + width, y + height};
533 RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height};
534
535 D3DLOCKED_RECT sourceLock = {0};
536 result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
537
538 if (FAILED(result))
539 {
540 ERR("Failed to lock the source surface (rectangle might be invalid).");
541 renderTargetData->Release();
542 surface->Release();
543 return error(GL_OUT_OF_MEMORY);
544 }
545
546 D3DLOCKED_RECT destLock = {0};
547 result = lock(&destLock, &destRect);
548
549 if (FAILED(result))
550 {
551 ERR("Failed to lock the destination surface (rectangle might be invalid).");
552 renderTargetData->UnlockRect();
553 renderTargetData->Release();
554 surface->Release();
555 return error(GL_OUT_OF_MEMORY);
556 }
557
558 if (destLock.pBits && sourceLock.pBits)
559 {
560 unsigned char *source = (unsigned char*)sourceLock.pBits;
561 unsigned char *dest = (unsigned char*)destLock.pBits;
562
563 switch (description.Format)
564 {
565 case D3DFMT_X8R8G8B8:
566 case D3DFMT_A8R8G8B8:
567 switch(getD3DFormat())
568 {
569 case D3DFMT_X8R8G8B8:
570 case D3DFMT_A8R8G8B8:
571 for(int y = 0; y < height; y++)
572 {
573 memcpy(dest, source, 4 * width);
574
575 source += sourceLock.Pitch;
576 dest += destLock.Pitch;
577 }
578 break;
579 case D3DFMT_L8:
580 for(int y = 0; y < height; y++)
581 {
582 for(int x = 0; x < width; x++)
583 {
584 dest[x] = source[x * 4 + 2];
585 }
586
587 source += sourceLock.Pitch;
588 dest += destLock.Pitch;
589 }
590 break;
591 case D3DFMT_A8L8:
592 for(int y = 0; y < height; y++)
593 {
594 for(int x = 0; x < width; x++)
595 {
596 dest[x * 2 + 0] = source[x * 4 + 2];
597 dest[x * 2 + 1] = source[x * 4 + 3];
598 }
599
600 source += sourceLock.Pitch;
601 dest += destLock.Pitch;
602 }
603 break;
604 default:
605 UNREACHABLE();
606 }
607 break;
608 case D3DFMT_R5G6B5:
609 switch(getD3DFormat())
610 {
611 case D3DFMT_X8R8G8B8:
612 for(int y = 0; y < height; y++)
613 {
614 for(int x = 0; x < width; x++)
615 {
616 unsigned short rgb = ((unsigned short*)source)[x];
617 unsigned char red = (rgb & 0xF800) >> 8;
618 unsigned char green = (rgb & 0x07E0) >> 3;
619 unsigned char blue = (rgb & 0x001F) << 3;
620 dest[x + 0] = blue | (blue >> 5);
621 dest[x + 1] = green | (green >> 6);
622 dest[x + 2] = red | (red >> 5);
623 dest[x + 3] = 0xFF;
624 }
625
626 source += sourceLock.Pitch;
627 dest += destLock.Pitch;
628 }
629 break;
630 case D3DFMT_L8:
631 for(int y = 0; y < height; y++)
632 {
633 for(int x = 0; x < width; x++)
634 {
635 unsigned char red = source[x * 2 + 1] & 0xF8;
636 dest[x] = red | (red >> 5);
637 }
638
639 source += sourceLock.Pitch;
640 dest += destLock.Pitch;
641 }
642 break;
643 default:
644 UNREACHABLE();
645 }
646 break;
647 case D3DFMT_A1R5G5B5:
648 switch(getD3DFormat())
649 {
650 case D3DFMT_X8R8G8B8:
651 for(int y = 0; y < height; y++)
652 {
653 for(int x = 0; x < width; x++)
654 {
655 unsigned short argb = ((unsigned short*)source)[x];
656 unsigned char red = (argb & 0x7C00) >> 7;
657 unsigned char green = (argb & 0x03E0) >> 2;
658 unsigned char blue = (argb & 0x001F) << 3;
659 dest[x + 0] = blue | (blue >> 5);
660 dest[x + 1] = green | (green >> 5);
661 dest[x + 2] = red | (red >> 5);
662 dest[x + 3] = 0xFF;
663 }
664
665 source += sourceLock.Pitch;
666 dest += destLock.Pitch;
667 }
668 break;
669 case D3DFMT_A8R8G8B8:
670 for(int y = 0; y < height; y++)
671 {
672 for(int x = 0; x < width; x++)
673 {
674 unsigned short argb = ((unsigned short*)source)[x];
675 unsigned char red = (argb & 0x7C00) >> 7;
676 unsigned char green = (argb & 0x03E0) >> 2;
677 unsigned char blue = (argb & 0x001F) << 3;
678 unsigned char alpha = (signed short)argb >> 15;
679 dest[x + 0] = blue | (blue >> 5);
680 dest[x + 1] = green | (green >> 5);
681 dest[x + 2] = red | (red >> 5);
682 dest[x + 3] = alpha;
683 }
684
685 source += sourceLock.Pitch;
686 dest += destLock.Pitch;
687 }
688 break;
689 case D3DFMT_L8:
690 for(int y = 0; y < height; y++)
691 {
692 for(int x = 0; x < width; x++)
693 {
694 unsigned char red = source[x * 2 + 1] & 0x7C;
695 dest[x] = (red << 1) | (red >> 4);
696 }
697
698 source += sourceLock.Pitch;
699 dest += destLock.Pitch;
700 }
701 break;
702 case D3DFMT_A8L8:
703 for(int y = 0; y < height; y++)
704 {
705 for(int x = 0; x < width; x++)
706 {
707 unsigned char red = source[x * 2 + 1] & 0x7C;
708 dest[x * 2 + 0] = (red << 1) | (red >> 4);
709 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
710 }
711
712 source += sourceLock.Pitch;
713 dest += destLock.Pitch;
714 }
715 break;
716 default:
717 UNREACHABLE();
718 }
719 break;
720 default:
721 UNREACHABLE();
722 }
723 }
724
725 unlock();
726 renderTargetData->UnlockRect();
727
728 renderTargetData->Release();
729 surface->Release();
730
731 mDirty = true;
732}
733
734}