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
22namespace rx
23{
24
25Image9::Image9()
26{
27    mSurface = NULL;
28    mRenderer = NULL;
29
30    mD3DPool = D3DPOOL_SYSTEMMEM;
31    mD3DFormat = D3DFMT_UNKNOWN;
32}
33
34Image9::~Image9()
35{
36    SafeRelease(mSurface);
37}
38
39void 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
77Image9 *Image9::makeImage9(Image *img)
78{
79    ASSERT(HAS_DYNAMIC_TYPE(rx::Image9*, img));
80    return static_cast<rx::Image9*>(img);
81}
82
83void 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
95void 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
126bool 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
163void 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
223HRESULT 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
240void Image9::unlock()
241{
242    if (mSurface)
243    {
244        HRESULT result = mSurface->UnlockRect();
245        UNUSED_ASSERTION_VARIABLE(result);
246        ASSERT(SUCCEEDED(result));
247    }
248}
249
250D3DFORMAT 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
259bool 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
266IDirect3DSurface9 *Image9::getSurface()
267{
268    createSurface();
269
270    return mSurface;
271}
272
273void Image9::setManagedSurface2D(TextureStorage *storage, int level)
274{
275    TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage);
276    setManagedSurface(storage9->getSurfaceLevel(level, false));
277}
278
279void 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
285void 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
304bool 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
311bool 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
318bool 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
325bool 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
332bool 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.
384void 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
416void 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
454void 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}
707