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