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