1/**************************************************************************
2 *
3 * Copyright 2012-2021 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
24 * of the Software.
25 *
26 **************************************************************************/
27
28/*
29 * DxgiFns.cpp --
30 *    DXGI related functions.
31 */
32
33#include <stdio.h>
34
35#include "DxgiFns.h"
36#include "Format.h"
37#include "State.h"
38
39#include "Debug.h"
40
41#include "util/format/u_format.h"
42
43
44/*
45 * ----------------------------------------------------------------------
46 *
47 * _Present --
48 *
49 *    This is turned into kernel callbacks rather than directly emitted
50 *    as fifo packets.
51 *
52 * ----------------------------------------------------------------------
53 */
54
55HRESULT APIENTRY
56_Present(DXGI_DDI_ARG_PRESENT *pPresentData)
57{
58
59   LOG_ENTRYPOINT();
60
61   struct pipe_context *pipe = CastPipeDevice(pPresentData->hDevice);
62   Resource *pSrcResource = CastResource(pPresentData->hSurfaceToPresent);
63
64   D3DKMT_PRESENT *pPresentInfo = (D3DKMT_PRESENT *)pPresentData->pDXGIContext;
65
66   HWND hWnd = pPresentInfo->hWindow;
67
68   if (0) {
69      DebugPrintf("  hWindow = 0x%08lx\n", pPresentInfo->hWindow);
70      if (pPresentInfo->Flags.SrcRectValid) {
71         DebugPrintf("  SrcRect.left = %li\n", pPresentInfo->SrcRect.left);
72         DebugPrintf("  SrcRect.top = %li\n", pPresentInfo->SrcRect.top);
73         DebugPrintf("  SrcRect.right = %li\n", pPresentInfo->SrcRect.right);
74         DebugPrintf("  SrcRect.bottom = %li\n", pPresentInfo->SrcRect.bottom);
75      }
76      if (pPresentInfo->Flags.DstRectValid) {
77         DebugPrintf("  DstRect.left = %li\n", pPresentInfo->DstRect.left);
78         DebugPrintf("  DstRect.top = %li\n", pPresentInfo->DstRect.top);
79         DebugPrintf("  DstRect.right = %li\n", pPresentInfo->DstRect.right);
80         DebugPrintf("  DstRect.bottom = %li\n", pPresentInfo->DstRect.bottom);
81      }
82   }
83
84   RECT rect;
85   if (!GetClientRect(hWnd, &rect)) {
86      DebugPrintf("Invalid window.\n");
87      return S_OK;
88   }
89
90   int windowWidth  = rect.right  - rect.left;
91   int windowHeight = rect.bottom - rect.top;
92
93   HDC hDC = GetDC(hWnd);
94
95   unsigned w = pSrcResource->resource->width0;
96   unsigned h = pSrcResource->resource->height0;
97
98   void *map;
99   struct pipe_transfer *transfer;
100   map = pipe_texture_map(pipe,
101                          pSrcResource->resource,
102                          0, 0, PIPE_MAP_READ,
103                          0, 0, w, h,
104                          &transfer);
105   if (map) {
106
107      BITMAPINFO bmi;
108
109      memset(&bmi, 0, sizeof bmi);
110      bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
111      bmi.bmiHeader.biWidth = w;
112      bmi.bmiHeader.biHeight= -(long)h;
113      bmi.bmiHeader.biPlanes = 1;
114      bmi.bmiHeader.biBitCount = 32;
115      bmi.bmiHeader.biCompression = BI_RGB;
116      bmi.bmiHeader.biSizeImage = 0;
117      bmi.bmiHeader.biXPelsPerMeter = 0;
118      bmi.bmiHeader.biYPelsPerMeter = 0;
119      bmi.bmiHeader.biClrUsed = 0;
120      bmi.bmiHeader.biClrImportant = 0;
121
122      DWORD *pixels = NULL;
123
124      // http://www.daniweb.com/software-development/cpp/code/241875/fast-animation-with-the-windows-gdi
125
126      HBITMAP hBmp = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (void**)&pixels, NULL, 0);
127
128      util_format_translate(
129            PIPE_FORMAT_B8G8R8X8_UNORM,
130            (void *)pixels, w * 4,
131            0, 0,
132            pSrcResource->resource->format,
133            map, transfer->stride,
134            0, 0, w, h);
135
136      if (0) {
137         /*
138          * Save a BMP for debugging.
139          */
140
141         FILE *fp = fopen("present.bmp", "wb");
142         if (fp) {
143            BITMAPFILEHEADER bmf;
144            bmf.bfType = 0x4d42;
145            bmf.bfSize = sizeof bmf + sizeof bmi + h * w * 4;
146            bmf.bfReserved1 = 0;
147            bmf.bfReserved2 = 0;
148            bmf.bfOffBits = sizeof bmf + sizeof bmi;
149
150            fwrite(&bmf, sizeof bmf, 1, fp);
151            fwrite(&bmi, sizeof bmi, 1, fp);
152            fwrite(pixels, h, w * 4, fp);
153            fclose(fp);
154         }
155      }
156
157      HDC hdcMem;
158      hdcMem = CreateCompatibleDC(hDC);
159      HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hBmp);
160
161      int iStretchMode = SetStretchBltMode(hDC, HALFTONE);
162
163      StretchBlt(hDC, 0, 0, windowWidth, windowHeight,
164                 hdcMem, 0, 0, w, h,
165                 SRCCOPY);
166
167      if (iStretchMode) {
168         SetStretchBltMode(hDC, iStretchMode);
169      }
170
171      SelectObject(hdcMem, hbmOld);
172      DeleteDC(hdcMem);
173      DeleteObject(hBmp);
174
175      pipe_texture_unmap(pipe, transfer);
176   }
177
178   ReleaseDC(hWnd, hDC);
179
180   return S_OK;
181}
182
183
184/*
185 * ----------------------------------------------------------------------
186 *
187 * _GetGammaCaps --
188 *
189 *    Return gamma capabilities.
190 *
191 * ----------------------------------------------------------------------
192 */
193
194HRESULT APIENTRY
195_GetGammaCaps( DXGI_DDI_ARG_GET_GAMMA_CONTROL_CAPS *GetCaps )
196{
197   LOG_ENTRYPOINT();
198
199   DXGI_GAMMA_CONTROL_CAPABILITIES *pCaps;
200
201   pCaps = GetCaps->pGammaCapabilities;
202
203   pCaps->ScaleAndOffsetSupported = FALSE;
204   pCaps->MinConvertedValue = 0.0;
205   pCaps->MaxConvertedValue = 1.0;
206   pCaps->NumGammaControlPoints = 17;
207
208   for (UINT i = 0; i < pCaps->NumGammaControlPoints; i++) {
209      pCaps->ControlPointPositions[i] = (float)i / (float)(pCaps->NumGammaControlPoints - 1);
210   }
211
212   return S_OK;
213}
214
215
216/*
217 * ----------------------------------------------------------------------
218 *
219 * _SetDisplayMode --
220 *
221 *    Set the resource that is used to scan out to the display.
222 *
223 * ----------------------------------------------------------------------
224 */
225
226HRESULT APIENTRY
227_SetDisplayMode( DXGI_DDI_ARG_SETDISPLAYMODE *SetDisplayMode )
228{
229   LOG_UNSUPPORTED_ENTRYPOINT();
230
231   return S_OK;
232}
233
234
235/*
236 * ----------------------------------------------------------------------
237 *
238 * _SetResourcePriority --
239 *
240 * ----------------------------------------------------------------------
241 */
242
243HRESULT APIENTRY
244_SetResourcePriority( DXGI_DDI_ARG_SETRESOURCEPRIORITY *SetResourcePriority )
245{
246   LOG_ENTRYPOINT();
247
248   /* ignore */
249
250   return S_OK;
251}
252
253
254/*
255 * ----------------------------------------------------------------------
256 *
257 * _QueryResourceResidency --
258 *
259 * ----------------------------------------------------------------------
260 */
261
262HRESULT APIENTRY
263_QueryResourceResidency( DXGI_DDI_ARG_QUERYRESOURCERESIDENCY *QueryResourceResidency )
264{
265   LOG_ENTRYPOINT();
266
267   for (UINT i = 0; i < QueryResourceResidency->Resources; ++i) {
268      QueryResourceResidency->pStatus[i] = DXGI_DDI_RESIDENCY_FULLY_RESIDENT;
269   }
270
271   return S_OK;
272}
273
274
275/*
276 * ----------------------------------------------------------------------
277 *
278 * _RotateResourceIdentities --
279 *
280 *    Rotate a list of resources by recreating their views with
281 *    the updated rotations.
282 *
283 * ----------------------------------------------------------------------
284 */
285
286HRESULT APIENTRY
287_RotateResourceIdentities( DXGI_DDI_ARG_ROTATE_RESOURCE_IDENTITIES *RotateResourceIdentities )
288{
289   LOG_ENTRYPOINT();
290
291   if (RotateResourceIdentities->Resources <= 1) {
292      return S_OK;
293   }
294
295   struct pipe_context *pipe = CastPipeDevice(RotateResourceIdentities->hDevice);
296   struct pipe_screen *screen = pipe->screen;
297
298   struct pipe_resource *resource0 = CastPipeResource(RotateResourceIdentities->pResources[0]);
299
300   assert(resource0);
301   LOG_UNSUPPORTED(resource0->last_level);
302
303   /*
304    * XXX: Copying is not very efficient, but it is much simpler than the
305    * alternative of recreating all views.
306    */
307
308   struct pipe_resource *temp_resource;
309   temp_resource = screen->resource_create(screen, resource0);
310   assert(temp_resource);
311   if (!temp_resource) {
312      return E_OUTOFMEMORY;
313   }
314
315   struct pipe_box src_box;
316   src_box.x = 0;
317   src_box.y = 0;
318   src_box.z = 0;
319   src_box.width  = resource0->width0;
320   src_box.height = resource0->height0;
321   src_box.depth  = resource0->depth0;
322
323   for (UINT i = 0; i < RotateResourceIdentities->Resources + 1; ++i) {
324      struct pipe_resource *src_resource;
325      struct pipe_resource *dst_resource;
326
327      if (i < RotateResourceIdentities->Resources) {
328         src_resource = CastPipeResource(RotateResourceIdentities->pResources[i]);
329      } else {
330         src_resource = temp_resource;
331      }
332
333      if (i > 0) {
334         dst_resource = CastPipeResource(RotateResourceIdentities->pResources[i - 1]);
335      } else {
336         dst_resource = temp_resource;
337      }
338
339      assert(dst_resource);
340      assert(src_resource);
341
342      pipe->resource_copy_region(pipe,
343                                 dst_resource,
344                                 0, // dst_level
345                                 0, 0, 0, // dst_x,y,z
346                                 src_resource,
347                                 0, // src_level
348                                 &src_box);
349   }
350
351   pipe_resource_reference(&temp_resource, NULL);
352
353   return S_OK;
354}
355
356
357/*
358 * ----------------------------------------------------------------------
359 *
360 * _Blt --
361 *
362 *    Do a blt between two subresources. Apply MSAA resolve, format
363 *    conversion and stretching.
364 *
365 * ----------------------------------------------------------------------
366 */
367
368HRESULT APIENTRY
369_Blt(DXGI_DDI_ARG_BLT *Blt)
370{
371   LOG_UNSUPPORTED_ENTRYPOINT();
372
373   return S_OK;
374}
375