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