]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/VirtioGpuDxe/Gop.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / VirtioGpuDxe / Gop.c
CommitLineData
8731debe
LE
1/** @file\r
2\r
3 EFI_GRAPHICS_OUTPUT_PROTOCOL member functions for the VirtIo GPU driver.\r
4\r
5 Copyright (C) 2016, Red Hat, Inc.\r
6\r
b26f0cf9 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
8731debe
LE
8\r
9**/\r
10\r
8731debe
LE
11#include <Library/MemoryAllocationLib.h>\r
12\r
13#include "VirtioGpu.h"\r
14\r
15/**\r
16 Release guest-side and host-side resources that are related to an initialized\r
17 VGPU_GOP.Gop.\r
18\r
19 param[in,out] VgpuGop The VGPU_GOP object to release resources for.\r
20\r
21 On input, the caller is responsible for having called\r
22 VgpuGop->Gop.SetMode() at least once successfully.\r
23 (This is equivalent to the requirement that\r
24 VgpuGop->BackingStore be non-NULL. It is also\r
25 equivalent to the requirement that VgpuGop->ResourceId\r
26 be nonzero.)\r
27\r
28 On output, resources will be released, and\r
29 VgpuGop->BackingStore and VgpuGop->ResourceId will be\r
30 nulled.\r
31\r
32 param[in] DisableHead Whether this head (scanout) currently references the\r
33 resource identified by VgpuGop->ResourceId. Only pass\r
34 FALSE when VgpuGop->Gop.SetMode() calls this function\r
35 while switching between modes, and set it to TRUE\r
36 every other time.\r
37**/\r
38VOID\r
39ReleaseGopResources (\r
ac0a286f
MK
40 IN OUT VGPU_GOP *VgpuGop,\r
41 IN BOOLEAN DisableHead\r
8731debe
LE
42 )\r
43{\r
ac0a286f 44 EFI_STATUS Status;\r
8731debe
LE
45\r
46 ASSERT (VgpuGop->ResourceId != 0);\r
47 ASSERT (VgpuGop->BackingStore != NULL);\r
48\r
49 //\r
50 // If any of the following host-side destruction steps fail, we can't get out\r
51 // of an inconsistent state, so we'll hang. In general errors in object\r
52 // destruction can hardly be recovered from.\r
53 //\r
54 if (DisableHead) {\r
55 //\r
56 // Dissociate head (scanout) #0 from the currently used 2D host resource,\r
57 // by setting ResourceId=0 for it.\r
58 //\r
59 Status = VirtioGpuSetScanout (\r
60 VgpuGop->ParentBus, // VgpuDev\r
ac0a286f
MK
61 0,\r
62 0,\r
63 0,\r
64 0, // X, Y, Width, Height\r
8731debe
LE
65 0, // ScanoutId\r
66 0 // ResourceId\r
67 );\r
68 //\r
69 // HACK BEGINS HERE\r
70 //\r
71 // According to the GPU Device section of the VirtIo specification, the\r
72 // above operation is valid:\r
73 //\r
74 // "The driver can use resource_id = 0 to disable a scanout."\r
75 //\r
76 // However, in practice QEMU does not allow us to disable head (scanout) #0\r
77 // -- it rejects the command with response code 0x1202\r
78 // (VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID). Looking at the QEMU source\r
79 // code, function virtio_gpu_set_scanout() in "hw/display/virtio-gpu.c",\r
80 // this appears fully intentional, despite not being documented in the\r
81 // spec.\r
82 //\r
83 // Surprisingly, ignoring the error here, and proceeding to release\r
84 // host-side resources that presumably underlie head (scanout) #0, work\r
85 // without any problems -- the driver survives repeated "disconnect" /\r
86 // "connect -r" commands in the UEFI shell.\r
87 //\r
88 // So, for now, let's just suppress the error.\r
89 //\r
90 Status = EFI_SUCCESS;\r
91 //\r
92 // HACK ENDS HERE\r
93 //\r
94\r
95 ASSERT_EFI_ERROR (Status);\r
96 if (EFI_ERROR (Status)) {\r
97 CpuDeadLoop ();\r
98 }\r
99 }\r
100\r
101 //\r
102 // Detach backing pages from the currently used 2D host resource.\r
103 //\r
104 Status = VirtioGpuResourceDetachBacking (\r
105 VgpuGop->ParentBus, // VgpuDev\r
106 VgpuGop->ResourceId // ResourceId\r
107 );\r
108 ASSERT_EFI_ERROR (Status);\r
109 if (EFI_ERROR (Status)) {\r
110 CpuDeadLoop ();\r
111 }\r
112\r
113 //\r
f10ae923 114 // Unmap and release backing pages.\r
8731debe 115 //\r
f10ae923
LE
116 VirtioGpuUnmapAndFreeBackingStore (\r
117 VgpuGop->ParentBus, // VgpuDev\r
118 VgpuGop->NumberOfPages, // NumberOfPages\r
119 VgpuGop->BackingStore, // HostAddress\r
120 VgpuGop->BackingStoreMap // Mapping\r
121 );\r
ac0a286f
MK
122 VgpuGop->BackingStore = NULL;\r
123 VgpuGop->NumberOfPages = 0;\r
f10ae923 124 VgpuGop->BackingStoreMap = NULL;\r
8731debe
LE
125\r
126 //\r
127 // Destroy the currently used 2D host resource.\r
128 //\r
129 Status = VirtioGpuResourceUnref (\r
130 VgpuGop->ParentBus, // VgpuDev\r
131 VgpuGop->ResourceId // ResourceId\r
132 );\r
133 ASSERT_EFI_ERROR (Status);\r
134 if (EFI_ERROR (Status)) {\r
135 CpuDeadLoop ();\r
136 }\r
ac0a286f 137\r
8731debe
LE
138 VgpuGop->ResourceId = 0;\r
139}\r
140\r
141//\r
142// The resolutions supported by this driver.\r
143//\r
144typedef struct {\r
ac0a286f
MK
145 UINT32 Width;\r
146 UINT32 Height;\r
8731debe
LE
147} GOP_RESOLUTION;\r
148\r
ac0a286f
MK
149STATIC CONST GOP_RESOLUTION mGopResolutions[] = {\r
150 { 640, 480 },\r
151 { 800, 480 },\r
152 { 800, 600 },\r
153 { 832, 624 },\r
154 { 960, 640 },\r
155 { 1024, 600 },\r
156 { 1024, 768 },\r
157 { 1152, 864 },\r
158 { 1152, 870 },\r
159 { 1280, 720 },\r
160 { 1280, 760 },\r
161 { 1280, 768 },\r
162 { 1280, 800 },\r
163 { 1280, 960 },\r
8731debe 164 { 1280, 1024 },\r
ac0a286f
MK
165 { 1360, 768 },\r
166 { 1366, 768 },\r
8731debe 167 { 1400, 1050 },\r
ac0a286f
MK
168 { 1440, 900 },\r
169 { 1600, 900 },\r
8731debe
LE
170 { 1600, 1200 },\r
171 { 1680, 1050 },\r
172 { 1920, 1080 },\r
173 { 1920, 1200 },\r
174 { 1920, 1440 },\r
175 { 2000, 2000 },\r
176 { 2048, 1536 },\r
177 { 2048, 2048 },\r
178 { 2560, 1440 },\r
179 { 2560, 1600 },\r
180 { 2560, 2048 },\r
181 { 2800, 2100 },\r
182 { 3200, 2400 },\r
183 { 3840, 2160 },\r
184 { 4096, 2160 },\r
185 { 7680, 4320 },\r
186 { 8192, 4320 },\r
187};\r
188\r
189//\r
190// Macro for casting VGPU_GOP.Gop to VGPU_GOP.\r
191//\r
192#define VGPU_GOP_FROM_GOP(GopPointer) \\r
193 CR (GopPointer, VGPU_GOP, Gop, VGPU_GOP_SIG)\r
194\r
195//\r
196// EFI_GRAPHICS_OUTPUT_PROTOCOL member functions.\r
197//\r
198STATIC\r
199EFI_STATUS\r
200EFIAPI\r
201GopQueryMode (\r
ac0a286f
MK
202 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,\r
203 IN UINT32 ModeNumber,\r
204 OUT UINTN *SizeOfInfo,\r
205 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info\r
8731debe
LE
206 )\r
207{\r
ac0a286f 208 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *GopModeInfo;\r
8731debe 209\r
5a5025e4 210 if (ModeNumber >= ARRAY_SIZE (mGopResolutions)) {\r
8731debe
LE
211 return EFI_INVALID_PARAMETER;\r
212 }\r
213\r
214 GopModeInfo = AllocateZeroPool (sizeof *GopModeInfo);\r
215 if (GopModeInfo == NULL) {\r
216 return EFI_OUT_OF_RESOURCES;\r
217 }\r
218\r
219 GopModeInfo->HorizontalResolution = mGopResolutions[ModeNumber].Width;\r
220 GopModeInfo->VerticalResolution = mGopResolutions[ModeNumber].Height;\r
221 GopModeInfo->PixelFormat = PixelBltOnly;\r
222 GopModeInfo->PixelsPerScanLine = mGopResolutions[ModeNumber].Width;\r
223\r
224 *SizeOfInfo = sizeof *GopModeInfo;\r
ac0a286f 225 *Info = GopModeInfo;\r
8731debe
LE
226 return EFI_SUCCESS;\r
227}\r
228\r
229STATIC\r
230EFI_STATUS\r
231EFIAPI\r
232GopSetMode (\r
ac0a286f
MK
233 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,\r
234 IN UINT32 ModeNumber\r
8731debe
LE
235 )\r
236{\r
ac0a286f
MK
237 VGPU_GOP *VgpuGop;\r
238 UINT32 NewResourceId;\r
239 UINTN NewNumberOfBytes;\r
240 UINTN NewNumberOfPages;\r
241 VOID *NewBackingStore;\r
242 EFI_PHYSICAL_ADDRESS NewBackingStoreDeviceAddress;\r
243 VOID *NewBackingStoreMap;\r
f10ae923 244\r
ac0a286f
MK
245 EFI_STATUS Status;\r
246 EFI_STATUS Status2;\r
8731debe 247\r
5a5025e4 248 if (ModeNumber >= ARRAY_SIZE (mGopResolutions)) {\r
8731debe
LE
249 return EFI_UNSUPPORTED;\r
250 }\r
251\r
252 VgpuGop = VGPU_GOP_FROM_GOP (This);\r
253\r
254 //\r
255 // Distinguish the first (internal) call from the other (protocol consumer)\r
256 // calls.\r
257 //\r
258 if (VgpuGop->ResourceId == 0) {\r
259 //\r
260 // Set up the Gop -> GopMode -> GopModeInfo pointer chain, and the other\r
261 // (nonzero) constant fields.\r
262 //\r
263 // No direct framebuffer access is supported, only Blt() is.\r
264 //\r
265 VgpuGop->Gop.Mode = &VgpuGop->GopMode;\r
266\r
ac0a286f
MK
267 VgpuGop->GopMode.MaxMode = (UINT32)(ARRAY_SIZE (mGopResolutions));\r
268 VgpuGop->GopMode.Info = &VgpuGop->GopModeInfo;\r
269 VgpuGop->GopMode.SizeOfInfo = sizeof VgpuGop->GopModeInfo;\r
8731debe
LE
270\r
271 VgpuGop->GopModeInfo.PixelFormat = PixelBltOnly;\r
272\r
273 //\r
274 // This is the first time we create a host side resource.\r
275 //\r
276 NewResourceId = 1;\r
277 } else {\r
278 //\r
279 // We already have an active host side resource. Create the new one without\r
280 // interfering with the current one, so that we can cleanly bail out on\r
281 // error, without disturbing the current graphics mode.\r
282 //\r
283 // The formula below will alternate between IDs 1 and 2.\r
284 //\r
285 NewResourceId = 3 - VgpuGop->ResourceId;\r
286 }\r
287\r
288 //\r
289 // Create the 2D host resource.\r
290 //\r
291 Status = VirtioGpuResourceCreate2d (\r
292 VgpuGop->ParentBus, // VgpuDev\r
293 NewResourceId, // ResourceId\r
294 VirtioGpuFormatB8G8R8X8Unorm, // Format\r
295 mGopResolutions[ModeNumber].Width, // Width\r
296 mGopResolutions[ModeNumber].Height // Height\r
297 );\r
298 if (EFI_ERROR (Status)) {\r
299 return Status;\r
300 }\r
301\r
302 //\r
f10ae923
LE
303 // Allocate, zero and map guest backing store, for bus master common buffer\r
304 // operation.\r
8731debe
LE
305 //\r
306 NewNumberOfBytes = mGopResolutions[ModeNumber].Width *\r
307 mGopResolutions[ModeNumber].Height * sizeof (UINT32);\r
308 NewNumberOfPages = EFI_SIZE_TO_PAGES (NewNumberOfBytes);\r
ac0a286f
MK
309 Status = VirtioGpuAllocateZeroAndMapBackingStore (\r
310 VgpuGop->ParentBus, // VgpuDev\r
311 NewNumberOfPages, // NumberOfPages\r
312 &NewBackingStore, // HostAddress\r
313 &NewBackingStoreDeviceAddress, // DeviceAddress\r
314 &NewBackingStoreMap // Mapping\r
315 );\r
f10ae923 316 if (EFI_ERROR (Status)) {\r
8731debe
LE
317 goto DestroyHostResource;\r
318 }\r
8731debe
LE
319\r
320 //\r
321 // Attach backing store to the host resource.\r
322 //\r
323 Status = VirtioGpuResourceAttachBacking (\r
5409c6ab
LE
324 VgpuGop->ParentBus, // VgpuDev\r
325 NewResourceId, // ResourceId\r
f10ae923 326 NewBackingStoreDeviceAddress, // BackingStoreDeviceAddress\r
5409c6ab 327 NewNumberOfPages // NumberOfPages\r
8731debe
LE
328 );\r
329 if (EFI_ERROR (Status)) {\r
f10ae923 330 goto UnmapAndFreeBackingStore;\r
8731debe
LE
331 }\r
332\r
333 //\r
334 // Point head (scanout) #0 to the host resource.\r
335 //\r
336 Status = VirtioGpuSetScanout (\r
337 VgpuGop->ParentBus, // VgpuDev\r
338 0, // X\r
339 0, // Y\r
340 mGopResolutions[ModeNumber].Width, // Width\r
341 mGopResolutions[ModeNumber].Height, // Height\r
342 0, // ScanoutId\r
343 NewResourceId // ResourceId\r
344 );\r
345 if (EFI_ERROR (Status)) {\r
346 goto DetachBackingStore;\r
347 }\r
348\r
349 //\r
350 // If this is not the first (i.e., internal) call, then we have to (a) flush\r
351 // the new resource to head (scanout) #0, after having flipped the latter to\r
352 // the former above, plus (b) release the old resources.\r
353 //\r
354 if (VgpuGop->ResourceId != 0) {\r
355 Status = VirtioGpuResourceFlush (\r
356 VgpuGop->ParentBus, // VgpuDev\r
357 0, // X\r
358 0, // Y\r
359 mGopResolutions[ModeNumber].Width, // Width\r
360 mGopResolutions[ModeNumber].Height, // Height\r
361 NewResourceId // ResourceId\r
362 );\r
363 if (EFI_ERROR (Status)) {\r
364 //\r
365 // Flip head (scanout) #0 back to the current resource. If this fails, we\r
366 // cannot continue, as this error occurs on the error path and is\r
367 // therefore non-recoverable.\r
368 //\r
369 Status2 = VirtioGpuSetScanout (\r
370 VgpuGop->ParentBus, // VgpuDev\r
371 0, // X\r
372 0, // Y\r
373 mGopResolutions[This->Mode->Mode].Width, // Width\r
374 mGopResolutions[This->Mode->Mode].Height, // Height\r
375 0, // ScanoutId\r
376 VgpuGop->ResourceId // ResourceId\r
377 );\r
378 ASSERT_EFI_ERROR (Status2);\r
379 if (EFI_ERROR (Status2)) {\r
380 CpuDeadLoop ();\r
381 }\r
ac0a286f 382\r
8731debe
LE
383 goto DetachBackingStore;\r
384 }\r
385\r
386 //\r
387 // Flush successful; release the old resources (without disabling head\r
388 // (scanout) #0).\r
389 //\r
390 ReleaseGopResources (VgpuGop, FALSE /* DisableHead */);\r
391 }\r
392\r
393 //\r
394 // This is either the first (internal) call when we have no old resources\r
395 // yet, or we've changed the mode successfully and released the old\r
396 // resources.\r
397 //\r
398 ASSERT (VgpuGop->ResourceId == 0);\r
399 ASSERT (VgpuGop->BackingStore == NULL);\r
400\r
ac0a286f
MK
401 VgpuGop->ResourceId = NewResourceId;\r
402 VgpuGop->BackingStore = NewBackingStore;\r
403 VgpuGop->NumberOfPages = NewNumberOfPages;\r
f10ae923 404 VgpuGop->BackingStoreMap = NewBackingStoreMap;\r
8731debe
LE
405\r
406 //\r
407 // Populate Mode and ModeInfo (mutable fields only).\r
408 //\r
ac0a286f 409 VgpuGop->GopMode.Mode = ModeNumber;\r
8731debe 410 VgpuGop->GopModeInfo.HorizontalResolution =\r
ac0a286f 411 mGopResolutions[ModeNumber].Width;\r
8731debe 412 VgpuGop->GopModeInfo.VerticalResolution = mGopResolutions[ModeNumber].Height;\r
ac0a286f 413 VgpuGop->GopModeInfo.PixelsPerScanLine = mGopResolutions[ModeNumber].Width;\r
8731debe
LE
414 return EFI_SUCCESS;\r
415\r
416DetachBackingStore:\r
417 Status2 = VirtioGpuResourceDetachBacking (VgpuGop->ParentBus, NewResourceId);\r
418 ASSERT_EFI_ERROR (Status2);\r
419 if (EFI_ERROR (Status2)) {\r
420 CpuDeadLoop ();\r
421 }\r
422\r
f10ae923
LE
423UnmapAndFreeBackingStore:\r
424 VirtioGpuUnmapAndFreeBackingStore (\r
425 VgpuGop->ParentBus, // VgpuDev\r
426 NewNumberOfPages, // NumberOfPages\r
427 NewBackingStore, // HostAddress\r
428 NewBackingStoreMap // Mapping\r
429 );\r
8731debe
LE
430\r
431DestroyHostResource:\r
432 Status2 = VirtioGpuResourceUnref (VgpuGop->ParentBus, NewResourceId);\r
433 ASSERT_EFI_ERROR (Status2);\r
434 if (EFI_ERROR (Status2)) {\r
435 CpuDeadLoop ();\r
436 }\r
437\r
438 return Status;\r
439}\r
440\r
441STATIC\r
442EFI_STATUS\r
443EFIAPI\r
444GopBlt (\r
ac0a286f
MK
445 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,\r
446 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL,\r
447 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,\r
448 IN UINTN SourceX,\r
449 IN UINTN SourceY,\r
450 IN UINTN DestinationX,\r
451 IN UINTN DestinationY,\r
452 IN UINTN Width,\r
453 IN UINTN Height,\r
454 IN UINTN Delta OPTIONAL\r
8731debe
LE
455 )\r
456{\r
ac0a286f
MK
457 VGPU_GOP *VgpuGop;\r
458 UINT32 CurrentHorizontal;\r
459 UINT32 CurrentVertical;\r
460 UINTN SegmentSize;\r
461 UINTN Y;\r
462 UINTN ResourceOffset;\r
463 EFI_STATUS Status;\r
464\r
465 VgpuGop = VGPU_GOP_FROM_GOP (This);\r
8731debe
LE
466 CurrentHorizontal = VgpuGop->GopModeInfo.HorizontalResolution;\r
467 CurrentVertical = VgpuGop->GopModeInfo.VerticalResolution;\r
468\r
469 //\r
470 // We can avoid pixel format conversion in the guest because the internal\r
471 // representation of EFI_GRAPHICS_OUTPUT_BLT_PIXEL and that of\r
472 // VirtioGpuFormatB8G8R8X8Unorm are identical.\r
473 //\r
474 SegmentSize = Width * sizeof (UINT32);\r
475\r
476 //\r
477 // Delta is relevant for operations that read a rectangle from, or write a\r
478 // rectangle to, BltBuffer.\r
479 //\r
480 // In these cases, Delta is the stride of BltBuffer, in bytes. If Delta is\r
481 // zero, then Width is the entire width of BltBuffer, and the stride is\r
482 // supposed to be calculated from Width.\r
483 //\r
ac0a286f
MK
484 if ((BltOperation == EfiBltVideoToBltBuffer) ||\r
485 (BltOperation == EfiBltBufferToVideo))\r
486 {\r
8731debe
LE
487 if (Delta == 0) {\r
488 Delta = SegmentSize;\r
489 }\r
490 }\r
491\r
492 //\r
493 // For operations that write to the display, check if the destination fits\r
494 // onto the display.\r
495 //\r
ac0a286f
MK
496 if ((BltOperation == EfiBltVideoFill) ||\r
497 (BltOperation == EfiBltBufferToVideo) ||\r
498 (BltOperation == EfiBltVideoToVideo))\r
499 {\r
500 if ((DestinationX > CurrentHorizontal) ||\r
501 (Width > CurrentHorizontal - DestinationX) ||\r
502 (DestinationY > CurrentVertical) ||\r
503 (Height > CurrentVertical - DestinationY))\r
504 {\r
8731debe
LE
505 return EFI_INVALID_PARAMETER;\r
506 }\r
507 }\r
508\r
509 //\r
510 // For operations that read from the display, check if the source fits onto\r
511 // the display.\r
512 //\r
ac0a286f
MK
513 if ((BltOperation == EfiBltVideoToBltBuffer) ||\r
514 (BltOperation == EfiBltVideoToVideo))\r
515 {\r
516 if ((SourceX > CurrentHorizontal) ||\r
517 (Width > CurrentHorizontal - SourceX) ||\r
518 (SourceY > CurrentVertical) ||\r
519 (Height > CurrentVertical - SourceY))\r
520 {\r
8731debe
LE
521 return EFI_INVALID_PARAMETER;\r
522 }\r
523 }\r
524\r
525 //\r
526 // Render the request. For requests that do not modify the display, there\r
527 // won't be further steps.\r
528 //\r
529 switch (BltOperation) {\r
ac0a286f
MK
530 case EfiBltVideoFill:\r
531 //\r
532 // Write data from the BltBuffer pixel (0, 0) directly to every pixel of\r
533 // the video display rectangle (DestinationX, DestinationY) (DestinationX +\r
534 // Width, DestinationY + Height). Only one pixel will be used from the\r
535 // BltBuffer. Delta is NOT used.\r
536 //\r
537 for (Y = 0; Y < Height; ++Y) {\r
538 SetMem32 (\r
539 VgpuGop->BackingStore +\r
8731debe 540 (DestinationY + Y) * CurrentHorizontal + DestinationX,\r
ac0a286f
MK
541 SegmentSize,\r
542 *(UINT32 *)BltBuffer\r
543 );\r
544 }\r
8731debe 545\r
ac0a286f 546 break;\r
8731debe 547\r
ac0a286f
MK
548 case EfiBltVideoToBltBuffer:\r
549 //\r
550 // Read data from the video display rectangle (SourceX, SourceY) (SourceX +\r
551 // Width, SourceY + Height) and place it in the BltBuffer rectangle\r
552 // (DestinationX, DestinationY ) (DestinationX + Width, DestinationY +\r
553 // Height). If DestinationX or DestinationY is not zero then Delta must be\r
554 // set to the length in bytes of a row in the BltBuffer.\r
555 //\r
556 for (Y = 0; Y < Height; ++Y) {\r
8731debe 557 CopyMem (\r
ac0a286f
MK
558 (UINT8 *)BltBuffer +\r
559 (DestinationY + Y) * Delta + DestinationX * sizeof *BltBuffer,\r
8731debe 560 VgpuGop->BackingStore +\r
ac0a286f 561 (SourceY + Y) * CurrentHorizontal + SourceX,\r
8731debe
LE
562 SegmentSize\r
563 );\r
564 }\r
ac0a286f
MK
565\r
566 return EFI_SUCCESS;\r
567\r
568 case EfiBltBufferToVideo:\r
569 //\r
570 // Write data from the BltBuffer rectangle (SourceX, SourceY) (SourceX +\r
571 // Width, SourceY + Height) directly to the video display rectangle\r
572 // (DestinationX, DestinationY) (DestinationX + Width, DestinationY +\r
573 // Height). If SourceX or SourceY is not zero then Delta must be set to the\r
574 // length in bytes of a row in the BltBuffer.\r
575 //\r
8731debe
LE
576 for (Y = 0; Y < Height; ++Y) {\r
577 CopyMem (\r
578 VgpuGop->BackingStore +\r
ac0a286f
MK
579 (DestinationY + Y) * CurrentHorizontal + DestinationX,\r
580 (UINT8 *)BltBuffer +\r
581 (SourceY + Y) * Delta + SourceX * sizeof *BltBuffer,\r
8731debe
LE
582 SegmentSize\r
583 );\r
584 }\r
8731debe 585\r
ac0a286f
MK
586 break;\r
587\r
588 case EfiBltVideoToVideo:\r
589 //\r
590 // Copy from the video display rectangle (SourceX, SourceY) (SourceX +\r
591 // Width, SourceY + Height) to the video display rectangle (DestinationX,\r
592 // DestinationY) (DestinationX + Width, DestinationY + Height). The\r
593 // BltBuffer and Delta are not used in this mode.\r
594 //\r
595 // A single invocation of CopyMem() handles overlap between source and\r
596 // destination (that is, within a single line), but for multiple\r
597 // invocations, we must handle overlaps.\r
598 //\r
599 if (SourceY < DestinationY) {\r
600 Y = Height;\r
601 while (Y > 0) {\r
602 --Y;\r
603 CopyMem (\r
604 VgpuGop->BackingStore +\r
605 (DestinationY + Y) * CurrentHorizontal + DestinationX,\r
606 VgpuGop->BackingStore +\r
607 (SourceY + Y) * CurrentHorizontal + SourceX,\r
608 SegmentSize\r
609 );\r
610 }\r
611 } else {\r
612 for (Y = 0; Y < Height; ++Y) {\r
613 CopyMem (\r
614 VgpuGop->BackingStore +\r
615 (DestinationY + Y) * CurrentHorizontal + DestinationX,\r
616 VgpuGop->BackingStore +\r
617 (SourceY + Y) * CurrentHorizontal + SourceX,\r
618 SegmentSize\r
619 );\r
620 }\r
621 }\r
622\r
623 break;\r
624\r
625 default:\r
626 return EFI_INVALID_PARAMETER;\r
8731debe
LE
627 }\r
628\r
629 //\r
630 // For operations that wrote to the display, submit the updated area to the\r
631 // host -- update the host resource from guest memory.\r
632 //\r
633 ResourceOffset = sizeof (UINT32) * (DestinationY * CurrentHorizontal +\r
634 DestinationX);\r
635 Status = VirtioGpuTransferToHost2d (\r
636 VgpuGop->ParentBus, // VgpuDev\r
637 (UINT32)DestinationX, // X\r
638 (UINT32)DestinationY, // Y\r
639 (UINT32)Width, // Width\r
640 (UINT32)Height, // Height\r
641 ResourceOffset, // Offset\r
642 VgpuGop->ResourceId // ResourceId\r
643 );\r
644 if (EFI_ERROR (Status)) {\r
645 return Status;\r
646 }\r
647\r
648 //\r
649 // Flush the updated resource to the display.\r
650 //\r
651 Status = VirtioGpuResourceFlush (\r
652 VgpuGop->ParentBus, // VgpuDev\r
653 (UINT32)DestinationX, // X\r
654 (UINT32)DestinationY, // Y\r
655 (UINT32)Width, // Width\r
656 (UINT32)Height, // Height\r
657 VgpuGop->ResourceId // ResourceId\r
658 );\r
659 return Status;\r
660}\r
661\r
662//\r
663// Template for initializing VGPU_GOP.Gop.\r
664//\r
ac0a286f 665CONST EFI_GRAPHICS_OUTPUT_PROTOCOL mGopTemplate = {\r
8731debe
LE
666 GopQueryMode,\r
667 GopSetMode,\r
668 GopBlt,\r
669 NULL // Mode, to be overwritten in the actual protocol instance\r
670};\r