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