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