audk/MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.c

720 lines
25 KiB
C

/** @file
FrameBufferBltLib - Library to perform blt operations on a frame buffer.
Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Uefi/UefiBaseType.h>
#include <Protocol/GraphicsOutput.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/FrameBufferBltLib.h>
struct FRAME_BUFFER_CONFIGURE {
UINTN ColorDepth;
UINTN WidthInBytes;
UINTN BytesPerPixel;
UINTN WidthInPixels;
UINTN Height;
UINT8 *FrameBuffer;
EFI_GRAPHICS_PIXEL_FORMAT PixelFormat;
EFI_PIXEL_BITMASK PixelMasks;
INT8 PixelShl[4]; // R-G-B-Rsvd
INT8 PixelShr[4]; // R-G-B-Rsvd
UINT8 LineBuffer[0];
};
CONST EFI_PIXEL_BITMASK mRgbPixelMasks = {
0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
};
CONST EFI_PIXEL_BITMASK mBgrPixelMasks = {
0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000
};
/**
Initialize the bit mask in frame buffer configure.
@param BitMask The bit mask of pixel.
@param BytesPerPixel Size in bytes of pixel.
@param PixelShl Left shift array.
@param PixelShr Right shift array.
**/
VOID
FrameBufferBltLibConfigurePixelFormat (
IN CONST EFI_PIXEL_BITMASK *BitMask,
OUT UINTN *BytesPerPixel,
OUT INT8 *PixelShl,
OUT INT8 *PixelShr
)
{
UINT8 Index;
UINT32 *Masks;
UINT32 MergedMasks;
ASSERT (BytesPerPixel != NULL);
MergedMasks = 0;
Masks = (UINT32*) BitMask;
for (Index = 0; Index < 3; Index++) {
ASSERT ((MergedMasks & Masks[Index]) == 0);
PixelShl[Index] = (INT8) HighBitSet32 (Masks[Index]) - 23 + (Index * 8);
if (PixelShl[Index] < 0) {
PixelShr[Index] = -PixelShl[Index];
PixelShl[Index] = 0;
} else {
PixelShr[Index] = 0;
}
DEBUG ((DEBUG_INFO, "%d: shl:%d shr:%d mask:%x\n", Index,
PixelShl[Index], PixelShr[Index], Masks[Index]));
MergedMasks = (UINT32) (MergedMasks | Masks[Index]);
}
MergedMasks = (UINT32) (MergedMasks | Masks[3]);
ASSERT (MergedMasks != 0);
*BytesPerPixel = (UINTN) ((HighBitSet32 (MergedMasks) + 7) / 8);
DEBUG ((DEBUG_INFO, "Bytes per pixel: %d\n", *BytesPerPixel));
}
/**
Create the configuration for a video frame buffer.
The configuration is returned in the caller provided buffer.
@param[in] FrameBuffer Pointer to the start of the frame buffer.
@param[in] FrameBufferInfo Describes the frame buffer characteristics.
@param[in,out] Configure The created configuration information.
@param[in,out] ConfigureSize Size of the configuration information.
@retval RETURN_SUCCESS The configuration was successful created.
@retval RETURN_BUFFER_TOO_SMALL The Configure is to too small. The required
size is returned in ConfigureSize.
@retval RETURN_UNSUPPORTED The requested mode is not supported by
this implementaion.
**/
RETURN_STATUS
EFIAPI
FrameBufferBltConfigure (
IN VOID *FrameBuffer,
IN EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *FrameBufferInfo,
IN OUT FRAME_BUFFER_CONFIGURE *Configure,
IN OUT UINTN *ConfigureSize
)
{
CONST EFI_PIXEL_BITMASK *BitMask;
UINTN BytesPerPixel;
INT8 PixelShl[4];
INT8 PixelShr[4];
if (ConfigureSize == NULL) {
return RETURN_INVALID_PARAMETER;
}
switch (FrameBufferInfo->PixelFormat) {
case PixelRedGreenBlueReserved8BitPerColor:
BitMask = &mRgbPixelMasks;
break;
case PixelBlueGreenRedReserved8BitPerColor:
BitMask = &mBgrPixelMasks;
break;
case PixelBitMask:
BitMask = &FrameBufferInfo->PixelInformation;
break;
case PixelBltOnly:
ASSERT (FrameBufferInfo->PixelFormat != PixelBltOnly);
return RETURN_UNSUPPORTED;
default:
ASSERT (FALSE);
return RETURN_INVALID_PARAMETER;
}
FrameBufferBltLibConfigurePixelFormat (BitMask, &BytesPerPixel, PixelShl, PixelShr);
if (*ConfigureSize < sizeof (FRAME_BUFFER_CONFIGURE)
+ FrameBufferInfo->HorizontalResolution * BytesPerPixel) {
*ConfigureSize = sizeof (FRAME_BUFFER_CONFIGURE)
+ FrameBufferInfo->HorizontalResolution * BytesPerPixel;
return RETURN_BUFFER_TOO_SMALL;
}
if (Configure == NULL) {
return RETURN_INVALID_PARAMETER;
}
CopyMem (&Configure->PixelMasks, BitMask, sizeof (*BitMask));
CopyMem (Configure->PixelShl, PixelShl, sizeof (PixelShl));
CopyMem (Configure->PixelShr, PixelShr, sizeof (PixelShr));
Configure->BytesPerPixel = BytesPerPixel;
Configure->PixelFormat = FrameBufferInfo->PixelFormat;
Configure->FrameBuffer = (UINT8*) FrameBuffer;
Configure->WidthInPixels = (UINTN) FrameBufferInfo->HorizontalResolution;
Configure->Height = (UINTN) FrameBufferInfo->VerticalResolution;
Configure->WidthInBytes = Configure->WidthInPixels * Configure->BytesPerPixel;
return RETURN_SUCCESS;
}
/**
Performs a UEFI Graphics Output Protocol Blt Video Fill.
@param[in] Configure Pointer to a configuration which was successfully
created by FrameBufferBltConfigure ().
@param[in] Color Color to fill the region with.
@param[in] DestinationX X location to start fill operation.
@param[in] DestinationY Y location to start fill operation.
@param[in] Width Width (in pixels) to fill.
@param[in] Height Height to fill.
@retval RETURN_INVALID_PARAMETER Invalid parameter was passed in.
@retval RETURN_SUCCESS The video was filled successfully.
**/
EFI_STATUS
FrameBufferBltLibVideoFill (
IN FRAME_BUFFER_CONFIGURE *Configure,
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Color,
IN UINTN DestinationX,
IN UINTN DestinationY,
IN UINTN Width,
IN UINTN Height
)
{
UINTN IndexX;
UINTN IndexY;
UINT8 *Destination;
UINT8 Uint8;
UINT32 Uint32;
UINT64 WideFill;
BOOLEAN UseWideFill;
BOOLEAN LineBufferReady;
UINTN Offset;
UINTN WidthInBytes;
UINTN SizeInBytes;
//
// BltBuffer to Video: Source is BltBuffer, destination is Video
//
if (DestinationY + Height > Configure->Height) {
DEBUG ((EFI_D_VERBOSE, "VideoFill: Past screen (Y)\n"));
return RETURN_INVALID_PARAMETER;
}
if (DestinationX + Width > Configure->WidthInPixels) {
DEBUG ((EFI_D_VERBOSE, "VideoFill: Past screen (X)\n"));
return RETURN_INVALID_PARAMETER;
}
if (Width == 0 || Height == 0) {
DEBUG ((EFI_D_VERBOSE, "VideoFill: Width or Height is 0\n"));
return RETURN_INVALID_PARAMETER;
}
WidthInBytes = Width * Configure->BytesPerPixel;
Uint32 = *(UINT32*) Color;
WideFill =
(UINT32) (
(((Uint32 << Configure->PixelShl[0]) >> Configure->PixelShr[0]) &
Configure->PixelMasks.RedMask) |
(((Uint32 << Configure->PixelShl[1]) >> Configure->PixelShr[1]) &
Configure->PixelMasks.GreenMask) |
(((Uint32 << Configure->PixelShl[2]) >> Configure->PixelShr[2]) &
Configure->PixelMasks.BlueMask)
);
DEBUG ((EFI_D_VERBOSE, "VideoFill: color=0x%x, wide-fill=0x%x\n",
Uint32, WideFill));
//
// If the size of the pixel data evenly divides the sizeof
// WideFill, then a wide fill operation can be used
//
UseWideFill = TRUE;
if ((sizeof (WideFill) % Configure->BytesPerPixel) == 0) {
for (IndexX = Configure->BytesPerPixel; IndexX < sizeof (WideFill); IndexX++) {
((UINT8*) &WideFill)[IndexX] = ((UINT8*) &WideFill)[IndexX % Configure->BytesPerPixel];
}
} else {
//
// If all the bytes in the pixel are the same value, then use
// a wide fill operation.
//
for (
IndexX = 1, Uint8 = ((UINT8*) &WideFill)[0];
IndexX < Configure->BytesPerPixel;
IndexX++) {
if (Uint8 != ((UINT8*) &WideFill)[IndexX]) {
UseWideFill = FALSE;
break;
}
}
if (UseWideFill) {
SetMem (&WideFill, sizeof (WideFill), Uint8);
}
}
if (UseWideFill && (DestinationX == 0) && (Width == Configure->WidthInPixels)) {
DEBUG ((EFI_D_VERBOSE, "VideoFill (wide, one-shot)\n"));
Offset = DestinationY * Configure->WidthInPixels;
Offset = Configure->BytesPerPixel * Offset;
Destination = Configure->FrameBuffer + Offset;
SizeInBytes = WidthInBytes * Height;
if (SizeInBytes >= 8) {
SetMem32 (Destination, SizeInBytes & ~3, (UINT32) WideFill);
SizeInBytes &= 3;
}
if (SizeInBytes > 0) {
SetMem (Destination, SizeInBytes, (UINT8) (UINTN) WideFill);
}
} else {
LineBufferReady = FALSE;
for (IndexY = DestinationY; IndexY < (Height + DestinationY); IndexY++) {
Offset = (IndexY * Configure->WidthInPixels) + DestinationX;
Offset = Configure->BytesPerPixel * Offset;
Destination = Configure->FrameBuffer + Offset;
if (UseWideFill && (((UINTN) Destination & 7) == 0)) {
DEBUG ((EFI_D_VERBOSE, "VideoFill (wide)\n"));
SizeInBytes = WidthInBytes;
if (SizeInBytes >= 8) {
SetMem64 (Destination, SizeInBytes & ~7, WideFill);
SizeInBytes &= 7;
}
if (SizeInBytes > 0) {
CopyMem (Destination, &WideFill, SizeInBytes);
}
} else {
DEBUG ((EFI_D_VERBOSE, "VideoFill (not wide)\n"));
if (!LineBufferReady) {
CopyMem (Configure->LineBuffer, &WideFill, Configure->BytesPerPixel);
for (IndexX = 1; IndexX < Width; ) {
CopyMem (
(Configure->LineBuffer + (IndexX * Configure->BytesPerPixel)),
Configure->LineBuffer,
MIN (IndexX, Width - IndexX) * Configure->BytesPerPixel
);
IndexX += MIN (IndexX, Width - IndexX);
}
LineBufferReady = TRUE;
}
CopyMem (Destination, Configure->LineBuffer, WidthInBytes);
}
}
}
return RETURN_SUCCESS;
}
/**
Performs a UEFI Graphics Output Protocol Blt Video to Buffer operation
with extended parameters.
@param[in] Configure Pointer to a configuration which was successfully
created by FrameBufferBltConfigure ().
@param[out] BltBuffer Output buffer for pixel color data.
@param[in] SourceX X location within video.
@param[in] SourceY Y location within video.
@param[in] DestinationX X location within BltBuffer.
@param[in] DestinationY Y location within BltBuffer.
@param[in] Width Width (in pixels).
@param[in] Height Height.
@param[in] Delta Number of bytes in a row of BltBuffer.
@retval RETURN_INVALID_PARAMETER Invalid parameter were passed in.
@retval RETURN_SUCCESS The Blt operation was performed successfully.
**/
RETURN_STATUS
FrameBufferBltLibVideoToBltBuffer (
IN FRAME_BUFFER_CONFIGURE *Configure,
OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
IN UINTN SourceX,
IN UINTN SourceY,
IN UINTN DestinationX,
IN UINTN DestinationY,
IN UINTN Width,
IN UINTN Height,
IN UINTN Delta
)
{
UINTN DstY;
UINTN SrcY;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
UINT8 *Source;
UINT8 *Destination;
UINTN IndexX;
UINT32 Uint32;
UINTN Offset;
UINTN WidthInBytes;
//
// Video to BltBuffer: Source is Video, destination is BltBuffer
//
if (SourceY + Height > Configure->Height) {
return RETURN_INVALID_PARAMETER;
}
if (SourceX + Width > Configure->WidthInPixels) {
return RETURN_INVALID_PARAMETER;
}
if (Width == 0 || Height == 0) {
return RETURN_INVALID_PARAMETER;
}
//
// If Delta is zero, then the entire BltBuffer is being used, so Delta is
// the number of bytes in each row of BltBuffer. Since BltBuffer is Width
// pixels size, the number of bytes in each row can be computed.
//
if (Delta == 0) {
Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
}
WidthInBytes = Width * Configure->BytesPerPixel;
//
// Video to BltBuffer: Source is Video, destination is BltBuffer
//
for (SrcY = SourceY, DstY = DestinationY;
DstY < (Height + DestinationY);
SrcY++, DstY++) {
Offset = (SrcY * Configure->WidthInPixels) + SourceX;
Offset = Configure->BytesPerPixel * Offset;
Source = Configure->FrameBuffer + Offset;
if (Configure->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) {
Destination = (UINT8 *) BltBuffer + (DstY * Delta) + (DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
} else {
Destination = Configure->LineBuffer;
}
CopyMem (Destination, Source, WidthInBytes);
if (Configure->PixelFormat != PixelBlueGreenRedReserved8BitPerColor) {
for (IndexX = 0; IndexX < Width; IndexX++) {
Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)
((UINT8 *) BltBuffer + (DstY * Delta) +
(DestinationX + IndexX) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
Uint32 = *(UINT32*) (Configure->LineBuffer + (IndexX * Configure->BytesPerPixel));
*(UINT32*) Blt =
(UINT32) (
(((Uint32 & Configure->PixelMasks.RedMask) >>
Configure->PixelShl[0]) << Configure->PixelShr[0]) |
(((Uint32 & Configure->PixelMasks.GreenMask) >>
Configure->PixelShl[1]) << Configure->PixelShr[1]) |
(((Uint32 & Configure->PixelMasks.BlueMask) >>
Configure->PixelShl[2]) << Configure->PixelShr[2])
);
}
}
}
return RETURN_SUCCESS;
}
/**
Performs a UEFI Graphics Output Protocol Blt Buffer to Video operation
with extended parameters.
@param[in] Configure Pointer to a configuration which was successfully
created by FrameBufferBltConfigure ().
@param[in] BltBuffer Output buffer for pixel color data.
@param[in] SourceX X location within BltBuffer.
@param[in] SourceY Y location within BltBuffer.
@param[in] DestinationX X location within video.
@param[in] DestinationY Y location within video.
@param[in] Width Width (in pixels).
@param[in] Height Height.
@param[in] Delta Number of bytes in a row of BltBuffer.
@retval RETURN_INVALID_PARAMETER Invalid parameter were passed in.
@retval RETURN_SUCCESS The Blt operation was performed successfully.
**/
RETURN_STATUS
FrameBufferBltLibBufferToVideo (
IN FRAME_BUFFER_CONFIGURE *Configure,
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
IN UINTN SourceX,
IN UINTN SourceY,
IN UINTN DestinationX,
IN UINTN DestinationY,
IN UINTN Width,
IN UINTN Height,
IN UINTN Delta
)
{
UINTN DstY;
UINTN SrcY;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
UINT8 *Source;
UINT8 *Destination;
UINTN IndexX;
UINT32 Uint32;
UINTN Offset;
UINTN WidthInBytes;
//
// BltBuffer to Video: Source is BltBuffer, destination is Video
//
if (DestinationY + Height > Configure->Height) {
return RETURN_INVALID_PARAMETER;
}
if (DestinationX + Width > Configure->WidthInPixels) {
return RETURN_INVALID_PARAMETER;
}
if (Width == 0 || Height == 0) {
return RETURN_INVALID_PARAMETER;
}
//
// If Delta is zero, then the entire BltBuffer is being used, so Delta is
// the number of bytes in each row of BltBuffer. Since BltBuffer is Width
// pixels size, the number of bytes in each row can be computed.
//
if (Delta == 0) {
Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
}
WidthInBytes = Width * Configure->BytesPerPixel;
for (SrcY = SourceY, DstY = DestinationY;
SrcY < (Height + SourceY);
SrcY++, DstY++) {
Offset = (DstY * Configure->WidthInPixels) + DestinationX;
Offset = Configure->BytesPerPixel * Offset;
Destination = Configure->FrameBuffer + Offset;
if (Configure->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) {
Source = (UINT8 *) BltBuffer + (SrcY * Delta);
} else {
for (IndexX = 0; IndexX < Width; IndexX++) {
Blt =
(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (
(UINT8 *) BltBuffer +
(SrcY * Delta) +
((SourceX + IndexX) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))
);
Uint32 = *(UINT32*) Blt;
*(UINT32*) (Configure->LineBuffer + (IndexX * Configure->BytesPerPixel)) =
(UINT32) (
(((Uint32 << Configure->PixelShl[0]) >> Configure->PixelShr[0]) &
Configure->PixelMasks.RedMask) |
(((Uint32 << Configure->PixelShl[1]) >> Configure->PixelShr[1]) &
Configure->PixelMasks.GreenMask) |
(((Uint32 << Configure->PixelShl[2]) >> Configure->PixelShr[2]) &
Configure->PixelMasks.BlueMask)
);
}
Source = Configure->LineBuffer;
}
CopyMem (Destination, Source, WidthInBytes);
}
return RETURN_SUCCESS;
}
/**
Performs a UEFI Graphics Output Protocol Blt Video to Video operation
@param[in] Configure Pointer to a configuration which was successfully
created by FrameBufferBltConfigure ().
@param[in] SourceX X location within video.
@param[in] SourceY Y location within video.
@param[in] DestinationX X location within video.
@param[in] DestinationY Y location within video.
@param[in] Width Width (in pixels).
@param[in] Height Height.
@retval RETURN_INVALID_PARAMETER Invalid parameter were passed in.
@retval RETURN_SUCCESS The Blt operation was performed successfully.
**/
RETURN_STATUS
FrameBufferBltLibVideoToVideo (
IN FRAME_BUFFER_CONFIGURE *Configure,
IN UINTN SourceX,
IN UINTN SourceY,
IN UINTN DestinationX,
IN UINTN DestinationY,
IN UINTN Width,
IN UINTN Height
)
{
UINT8 *Source;
UINT8 *Destination;
UINTN Offset;
UINTN WidthInBytes;
INTN LineStride;
//
// Video to Video: Source is Video, destination is Video
//
if (SourceY + Height > Configure->Height) {
return RETURN_INVALID_PARAMETER;
}
if (SourceX + Width > Configure->WidthInPixels) {
return RETURN_INVALID_PARAMETER;
}
if (DestinationY + Height > Configure->Height) {
return RETURN_INVALID_PARAMETER;
}
if (DestinationX + Width > Configure->WidthInPixels) {
return RETURN_INVALID_PARAMETER;
}
if (Width == 0 || Height == 0) {
return RETURN_INVALID_PARAMETER;
}
WidthInBytes = Width * Configure->BytesPerPixel;
Offset = (SourceY * Configure->WidthInPixels) + SourceX;
Offset = Configure->BytesPerPixel * Offset;
Source = Configure->FrameBuffer + Offset;
Offset = (DestinationY * Configure->WidthInPixels) + DestinationX;
Offset = Configure->BytesPerPixel * Offset;
Destination = Configure->FrameBuffer + Offset;
LineStride = Configure->WidthInBytes;
if (Destination > Source) {
//
// Copy from last line to avoid source is corrupted by copying
//
Source += Height * LineStride;
Destination += Height * LineStride;
LineStride = -LineStride;
}
while (Height-- > 0) {
CopyMem (Destination, Source, WidthInBytes);
Source += LineStride;
Destination += LineStride;
}
return RETURN_SUCCESS;
}
/**
Performs a UEFI Graphics Output Protocol Blt operation.
@param[in] Configure Pointer to a configuration which was successfully
created by FrameBufferBltConfigure ().
@param[in,out] BltBuffer The data to transfer to screen.
@param[in] BltOperation The operation to perform.
@param[in] SourceX The X coordinate of the source for BltOperation.
@param[in] SourceY The Y coordinate of the source for BltOperation.
@param[in] DestinationX The X coordinate of the destination for
BltOperation.
@param[in] DestinationY The Y coordinate of the destination for
BltOperation.
@param[in] Width The width of a rectangle in the blt rectangle
in pixels.
@param[in] Height The height of a rectangle in the blt rectangle
in pixels.
@param[in] Delta Not used for EfiBltVideoFill and
EfiBltVideoToVideo operation. If a Delta of 0
is used, the entire BltBuffer will be operated
on. If a subrectangle of the BltBuffer is
used, then Delta represents the number of
bytes in a row of the BltBuffer.
@retval RETURN_INVALID_PARAMETER Invalid parameter were passed in.
@retval RETURN_SUCCESS The Blt operation was performed successfully.
**/
RETURN_STATUS
EFIAPI
FrameBufferBlt (
IN FRAME_BUFFER_CONFIGURE *Configure,
IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
IN UINTN SourceX,
IN UINTN SourceY,
IN UINTN DestinationX,
IN UINTN DestinationY,
IN UINTN Width,
IN UINTN Height,
IN UINTN Delta
)
{
if (Configure == NULL) {
return RETURN_INVALID_PARAMETER;
}
switch (BltOperation) {
case EfiBltVideoToBltBuffer:
return FrameBufferBltLibVideoToBltBuffer (
Configure,
BltBuffer,
SourceX,
SourceY,
DestinationX,
DestinationY,
Width,
Height,
Delta
);
case EfiBltVideoToVideo:
return FrameBufferBltLibVideoToVideo (
Configure,
SourceX,
SourceY,
DestinationX,
DestinationY,
Width,
Height
);
case EfiBltVideoFill:
return FrameBufferBltLibVideoFill (
Configure,
BltBuffer,
DestinationX,
DestinationY,
Width,
Height
);
case EfiBltBufferToVideo:
return FrameBufferBltLibBufferToVideo (
Configure,
BltBuffer,
SourceX,
SourceY,
DestinationX,
DestinationY,
Width,
Height,
Delta
);
default:
return RETURN_INVALID_PARAMETER;
}
}