VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaGraphicsOutput.c@ 67356

Last change on this file since 67356 was 67356, checked in by vboxsync, 8 years ago

EFI/Firmware: Eliminate the use of buffers in the blitting code (especially the full frame buffer for video to video blitting was really hurting as for high resolutions it needed a lot of RAM), primarily by cleaning up the code to be for 32bpp only, which it already was previously. Fixed UGA mode initialization, as it only pretended to set up the specified mode, but actually was never using anything else but mode 0 due to logical flaws.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.7 KB
Line 
1/* $Id: VBoxVgaGraphicsOutput.c 67356 2017-06-13 11:22:15Z vboxsync $ */
2/** @file
3 * VBoxVgaGraphicsOutput.c
4 */
5
6/*
7 * Copyright (C) 2009-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27/*
28 This code is based on:
29
30Copyright (c) 2007, Intel Corporation
31All rights reserved. This program and the accompanying materials
32are licensed and made available under the terms and conditions of the BSD License
33which accompanies this distribution. The full text of the license may be found at
34http://opensource.org/licenses/bsd-license.php
35
36THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
37WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
38
39Module Name:
40
41 UefiVBoxVgaGraphicsOutput.c
42
43Abstract:
44
45 This file produces the graphics abstraction of Graphics Output Protocol. It is called by
46 VBoxVga.c file which deals with the EFI 1.1 driver model.
47 This file just does graphics.
48
49*/
50#include "VBoxVga.h"
51#include <IndustryStandard/Acpi.h>
52
53
54STATIC
55VOID
56VBoxVgaCompleteModeInfo (
57 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info
58 )
59{
60 Info->Version = 0;
61 Info->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
62 Info->PixelsPerScanLine = Info->HorizontalResolution;
63}
64
65
66STATIC
67EFI_STATUS
68VBoxVgaCompleteModeData (
69 IN VBOX_VGA_PRIVATE_DATA *Private,
70 OUT EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode
71 )
72{
73 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
74 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *FrameBufDesc;
75
76 Info = Mode->Info;
77 VBoxVgaCompleteModeInfo (Info);
78
79 Private->PciIo->GetBarAttributes (
80 Private->PciIo,
81 0,
82 NULL,
83 (VOID**) &FrameBufDesc
84 );
85
86 DEBUG((DEBUG_INFO, "%a:%d FrameBufferBase:%x\n", __FILE__, __LINE__, FrameBufDesc->AddrRangeMin));
87 Mode->FrameBufferBase = FrameBufDesc->AddrRangeMin;
88 Mode->FrameBufferSize = Info->PixelsPerScanLine * Info->VerticalResolution
89 * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL); /* 32bpp only! */
90
91 return EFI_SUCCESS;
92}
93
94
95//
96// Graphics Output Protocol Member Functions
97//
98EFI_STATUS
99EFIAPI
100VBoxVgaGraphicsOutputQueryMode (
101 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
102 IN UINT32 ModeNumber,
103 OUT UINTN *SizeOfInfo,
104 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
105 )
106/*++
107
108Routine Description:
109
110 Graphics Output protocol interface to query video mode
111
112 Arguments:
113 This - Protocol instance pointer.
114 ModeNumber - The mode number to return information on.
115 Info - Caller allocated buffer that returns information about ModeNumber.
116 SizeOfInfo - A pointer to the size, in bytes, of the Info buffer.
117
118 Returns:
119 EFI_SUCCESS - Mode information returned.
120 EFI_BUFFER_TOO_SMALL - The Info buffer was too small.
121 EFI_DEVICE_ERROR - A hardware error occurred trying to retrieve the video mode.
122 EFI_NOT_STARTED - Video display is not initialized. Call SetMode ()
123 EFI_INVALID_PARAMETER - One of the input args was NULL.
124
125--*/
126{
127 VBOX_VGA_PRIVATE_DATA *Private;
128
129 Private = VBOX_VGA_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);
130
131 if (Private->HardwareNeedsStarting) {
132 return EFI_NOT_STARTED;
133 }
134
135 if (Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {
136 return EFI_INVALID_PARAMETER;
137 }
138
139 *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
140 if (*Info == NULL) {
141 return EFI_OUT_OF_RESOURCES;
142 }
143
144 *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
145
146 (*Info)->HorizontalResolution = Private->ModeData[ModeNumber].HorizontalResolution;
147 (*Info)->VerticalResolution = Private->ModeData[ModeNumber].VerticalResolution;
148 VBoxVgaCompleteModeInfo (*Info);
149
150 return EFI_SUCCESS;
151}
152
153EFI_STATUS
154EFIAPI
155VBoxVgaGraphicsOutputSetMode (
156 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
157 IN UINT32 ModeNumber
158 )
159/*++
160
161Routine Description:
162
163 Graphics Output protocol interface to set video mode
164
165 Arguments:
166 This - Protocol instance pointer.
167 ModeNumber - The mode number to be set.
168
169 Returns:
170 EFI_SUCCESS - Graphics mode was changed.
171 EFI_DEVICE_ERROR - The device had an error and could not complete the request.
172 EFI_UNSUPPORTED - ModeNumber is not supported by this device.
173
174--*/
175{
176 VBOX_VGA_PRIVATE_DATA *Private;
177 VBOX_VGA_MODE_DATA *ModeData;
178
179 Private = VBOX_VGA_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);
180
181 DEBUG((DEBUG_INFO, "%a:%d mode:%d\n", __FILE__, __LINE__, ModeNumber));
182 if (ModeNumber >= This->Mode->MaxMode) {
183 return EFI_UNSUPPORTED;
184 }
185
186 ModeData = &Private->ModeData[ModeNumber];
187
188 InitializeGraphicsMode (Private, &VBoxVgaVideoModes[ModeData->ModeNumber]);
189
190 This->Mode->Mode = ModeNumber;
191 This->Mode->Info->HorizontalResolution = ModeData->HorizontalResolution;
192 This->Mode->Info->VerticalResolution = ModeData->VerticalResolution;
193 This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
194
195 VBoxVgaCompleteModeData (Private, This->Mode);
196
197 Private->HardwareNeedsStarting = FALSE;
198 /* update current mode */
199 Private->CurrentMode = ModeNumber;
200
201 return EFI_SUCCESS;
202}
203
204EFI_STATUS
205EFIAPI
206VBoxVgaGraphicsOutputBlt (
207 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
208 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
209 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
210 IN UINTN SourceX,
211 IN UINTN SourceY,
212 IN UINTN DestinationX,
213 IN UINTN DestinationY,
214 IN UINTN Width,
215 IN UINTN Height,
216 IN UINTN Delta
217 )
218/*++
219
220Routine Description:
221
222 Graphics Output protocol instance to block transfer for CirrusLogic device
223
224Arguments:
225
226 This - Pointer to Graphics Output protocol instance
227 BltBuffer - The data to transfer to screen
228 BltOperation - The operation to perform
229 SourceX - The X coordinate of the source for BltOperation
230 SourceY - The Y coordinate of the source for BltOperation
231 DestinationX - The X coordinate of the destination for BltOperation
232 DestinationY - The Y coordinate of the destination for BltOperation
233 Width - The width of a rectangle in the blt rectangle in pixels
234 Height - The height of a rectangle in the blt rectangle in pixels
235 Delta - Not used for EfiBltVideoFill and EfiBltVideoToVideo operation.
236 If a Delta of 0 is used, the entire BltBuffer will be operated on.
237 If a subrectangle of the BltBuffer is used, then Delta represents
238 the number of bytes in a row of the BltBuffer.
239
240Returns:
241
242 EFI_INVALID_PARAMETER - Invalid parameter passed in
243 EFI_SUCCESS - Blt operation success
244
245--*/
246{
247 VBOX_VGA_PRIVATE_DATA *Private;
248 EFI_TPL OriginalTPL;
249 UINTN DstY;
250 UINTN SrcY;
251 UINT32 CurrentMode;
252 UINTN ScreenWidth;
253 UINTN ScreenHeight;
254 EFI_STATUS Status;
255
256 Private = VBOX_VGA_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);
257 CurrentMode = This->Mode->Mode;
258 ScreenWidth = Private->ModeData[CurrentMode].HorizontalResolution;
259 ScreenHeight = Private->ModeData[CurrentMode].VerticalResolution;
260
261 if ((BltOperation < 0) || (BltOperation >= EfiGraphicsOutputBltOperationMax)) {
262 return EFI_INVALID_PARAMETER;
263 }
264 if (Width == 0 || Height == 0) {
265 return EFI_INVALID_PARAMETER;
266 }
267
268 //
269 // If Delta is zero, then the entire BltBuffer is being used, so Delta
270 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
271 // the number of bytes in each row can be computed.
272 //
273 if (Delta == 0) {
274 Delta = Width * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
275 }
276 // code below assumes a Delta value in pixels, not bytes
277 Delta /= sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
278
279 //
280 // Make sure the SourceX, SourceY, DestinationX, DestinationY, Width, and Height parameters
281 // are valid for the operation and the current screen geometry.
282 //
283 if (BltOperation == EfiBltVideoToBltBuffer || BltOperation == EfiBltVideoToVideo) {
284 if (SourceY + Height > ScreenHeight) {
285 return EFI_INVALID_PARAMETER;
286 }
287
288 if (SourceX + Width > ScreenWidth) {
289 return EFI_INVALID_PARAMETER;
290 }
291 }
292 if (BltOperation == EfiBltBufferToVideo || BltOperation == EfiBltVideoToVideo || BltOperation == EfiBltVideoFill) {
293 if (DestinationY + Height > ScreenHeight) {
294 return EFI_INVALID_PARAMETER;
295 }
296
297 if (DestinationX + Width > ScreenWidth) {
298 return EFI_INVALID_PARAMETER;
299 }
300 }
301
302 //
303 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
304 // We would not want a timer based event (Cursor, ...) to come in while we are
305 // doing this operation.
306 //
307 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
308
309 switch (BltOperation) {
310 case EfiBltVideoToBltBuffer:
311 //
312 // Video to BltBuffer: Source is Video, destination is BltBuffer
313 //
314 for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY) && BltBuffer; SrcY++, DstY++) {
315 /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
316 Status = Private->PciIo->Mem.Read (
317 Private->PciIo,
318 EfiPciIoWidthUint32,
319 0,
320 ((SrcY * ScreenWidth) + SourceX) * 4,
321 Width,
322 BltBuffer + (DstY * Delta) + DestinationX
323 );
324 ASSERT_EFI_ERROR((Status));
325 }
326 break;
327
328 case EfiBltBufferToVideo:
329 //
330 // BltBuffer to Video: Source is BltBuffer, destination is Video
331 //
332 for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
333 /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
334 Status = Private->PciIo->Mem.Write (
335 Private->PciIo,
336 EfiPciIoWidthUint32,
337 0,
338 ((DstY * ScreenWidth) + DestinationX) * 4,
339 Width,
340 BltBuffer + (SrcY * Delta) + SourceX
341 );
342 ASSERT_EFI_ERROR((Status));
343 }
344 break;
345
346 case EfiBltVideoToVideo:
347 //
348 // Video to Video: Source is Video, destination is Video
349 //
350 if (DestinationY <= SourceY) {
351 // forward copy
352 for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
353 /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
354 Status = Private->PciIo->CopyMem (
355 Private->PciIo,
356 EfiPciIoWidthUint32,
357 0,
358 ((DstY * ScreenWidth) + DestinationX) * 4,
359 0,
360 ((SrcY * ScreenWidth) + SourceX) * 4,
361 Width
362 );
363 ASSERT_EFI_ERROR((Status));
364 }
365 } else {
366 // reverse copy
367 for (SrcY = SourceY + Height - 1, DstY = DestinationY + Height - 1; SrcY >= SourceY && SrcY <= SourceY + Height - 1; SrcY--, DstY--) {
368 /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
369 Status = Private->PciIo->CopyMem (
370 Private->PciIo,
371 EfiPciIoWidthUint32,
372 0,
373 ((DstY * ScreenWidth) + DestinationX) * 4,
374 0,
375 ((SrcY * ScreenWidth) + SourceX) * 4,
376 Width
377 );
378 ASSERT_EFI_ERROR((Status));
379 }
380 }
381 break;
382
383 case EfiBltVideoFill:
384 //
385 // Video Fill: Source is BltBuffer, destination is Video
386 //
387 if (DestinationX == 0 && Width == ScreenWidth) {
388 // @todo assumes that color depth is 32 (*4, EfiPciIoWidthFillUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
389 Status = Private->PciIo->Mem.Write (
390 Private->PciIo,
391 EfiPciIoWidthFillUint32,
392 0,
393 DestinationY * ScreenWidth * 4,
394 (Width * Height),
395 BltBuffer
396 );
397 ASSERT_EFI_ERROR((Status));
398 } else {
399 for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
400 // @todo assumes that color depth is 32 (*4, EfiPciIoWidthFillUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
401 Status = Private->PciIo->Mem.Write (
402 Private->PciIo,
403 EfiPciIoWidthFillUint32,
404 0,
405 ((DstY * ScreenWidth) + DestinationX) * 4,
406 Width,
407 BltBuffer
408 );
409 ASSERT_EFI_ERROR((Status));
410 }
411 }
412 break;
413
414 default:
415 ASSERT (FALSE);
416 }
417
418 gBS->RestoreTPL (OriginalTPL);
419
420 return EFI_SUCCESS;
421}
422
423EFI_STATUS
424VBoxVgaGraphicsOutputConstructor (
425 VBOX_VGA_PRIVATE_DATA *Private
426 )
427{
428 EFI_STATUS Status;
429 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
430 UINT32 GopMode = 2;
431
432 GraphicsOutput = &Private->GraphicsOutput;
433 GraphicsOutput->QueryMode = VBoxVgaGraphicsOutputQueryMode;
434 GraphicsOutput->SetMode = VBoxVgaGraphicsOutputSetMode;
435 GraphicsOutput->Blt = VBoxVgaGraphicsOutputBlt;
436
437 //
438 // Initialize the private data
439 //
440 Status = gBS->AllocatePool (
441 EfiBootServicesData,
442 sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE),
443 (VOID **) &Private->GraphicsOutput.Mode
444 );
445 if (EFI_ERROR (Status)) {
446 return Status;
447 }
448 Status = gBS->AllocatePool (
449 EfiBootServicesData,
450 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION),
451 (VOID **) &Private->GraphicsOutput.Mode->Info
452 );
453 if (EFI_ERROR (Status)) {
454 return Status;
455 }
456 Private->GraphicsOutput.Mode->MaxMode = (UINT32) Private->MaxMode;
457 Private->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
458 Private->HardwareNeedsStarting = TRUE;
459
460 //
461 // Initialize the hardware
462 //
463 VBoxVgaGetVmVariable(EFI_INFO_INDEX_GOP_MODE, (CHAR8 *)&GopMode, sizeof(GopMode));
464
465 GraphicsOutput->SetMode (GraphicsOutput, GopMode);
466
467 DrawLogo (
468 Private,
469 Private->ModeData[Private->GraphicsOutput.Mode->Mode].HorizontalResolution,
470 Private->ModeData[Private->GraphicsOutput.Mode->Mode].VerticalResolution
471 );
472
473 PcdSet32(PcdVideoHorizontalResolution, Private->ModeData[Private->GraphicsOutput.Mode->Mode].HorizontalResolution);
474 PcdSet32(PcdVideoVerticalResolution, Private->ModeData[Private->GraphicsOutput.Mode->Mode].VerticalResolution);
475
476 return EFI_SUCCESS;
477}
478
479EFI_STATUS
480VBoxVgaGraphicsOutputDestructor (
481 VBOX_VGA_PRIVATE_DATA *Private
482 )
483/*++
484
485Routine Description:
486
487Arguments:
488
489Returns:
490
491 None
492
493--*/
494{
495 if (Private->GraphicsOutput.Mode != NULL) {
496 if (Private->GraphicsOutput.Mode->Info != NULL) {
497 gBS->FreePool (Private->GraphicsOutput.Mode->Info);
498 }
499 gBS->FreePool (Private->GraphicsOutput.Mode);
500 }
501
502 return EFI_SUCCESS;
503}
504
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette