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 ®ion)
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