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