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