diff --git a/src/nanoFramework.Graphics/Graphics/Displays/DisplayInterface.h b/src/nanoFramework.Graphics/Graphics/Displays/DisplayInterface.h index e7f8499806..e94cfb72bc 100644 --- a/src/nanoFramework.Graphics/Graphics/Displays/DisplayInterface.h +++ b/src/nanoFramework.Graphics/Graphics/Displays/DisplayInterface.h @@ -1,4 +1,4 @@ -// +// // Copyright (c) .NET Foundation and Contributors // See LICENSE file in the project root for full license information. // @@ -88,6 +88,13 @@ struct DisplayInterface CLR_UINT32 height, CLR_UINT32 stride, bool doByteSwap); + void SendData18Windowed( + CLR_UINT16 *data, + CLR_UINT32 startX, + CLR_UINT32 startY, + CLR_UINT32 width, + CLR_UINT32 height, + CLR_UINT32 stride); void FillData16(CLR_UINT16 fillValue, CLR_UINT32 fillLength); void SetCommandMode(int mode); }; diff --git a/src/nanoFramework.Graphics/Graphics/Displays/Generic_SPI.cpp b/src/nanoFramework.Graphics/Graphics/Displays/Generic_SPI.cpp index 0e72449eb5..3cc4042012 100644 --- a/src/nanoFramework.Graphics/Graphics/Displays/Generic_SPI.cpp +++ b/src/nanoFramework.Graphics/Graphics/Displays/Generic_SPI.cpp @@ -1,4 +1,4 @@ -// +// // Copyright (c) .NET Foundation and Contributors // Portions Copyright (c) Microsoft Corporation. All rights reserved. // See LICENSE file in the project root for full license information. @@ -260,7 +260,16 @@ void DisplayDriver::Clear() g_DisplayInterface.SendCommand(1, g_DisplayInterfaceConfig.GenericDriverCommands.MemoryWrite); - g_DisplayInterface.FillData16(0, Attributes.Width * Attributes.Height); + if (Attributes.BitsPerPixel <= 16) + { + // 2 bytes per pixel + g_DisplayInterface.FillData16(0, Attributes.Width * Attributes.Height); + } + else + { + // 3 bytes per pixel + g_DisplayInterface.FillData16(0, (Attributes.Width * Attributes.Height * 3 + 1) / 2); + } } else { @@ -289,8 +298,6 @@ void DisplayDriver::BitBlt( int screenY, CLR_UINT32 data[]) { - // 16 bit colour RRRRRGGGGGGBBBBB mode 565 - ASSERT((screenX >= 0) && ((screenX + width) <= Attributes.Width)); ASSERT((screenY >= 0) && ((screenY + height) <= Attributes.Height)); @@ -298,7 +305,16 @@ void DisplayDriver::BitBlt( g_DisplayInterface.SendCommand(1, g_DisplayInterfaceConfig.GenericDriverCommands.MemoryWrite); - g_DisplayInterface.SendData16Windowed((CLR_UINT16 *)&data[0], srcX, srcY, width, height, stride, true); + if (Attributes.BitsPerPixel <= 16) + { + // 16-bit / two byte pixel formats. RGB mode 565 + g_DisplayInterface.SendData16Windowed((CLR_UINT16 *)&data[0], srcX, srcY, width, height, stride, true); + } + else + { + // 18-bit / three byte pixel formats. RGB mode 666 + g_DisplayInterface.SendData18Windowed((CLR_UINT16 *)&data[0], srcX, srcY, width, height, stride); + } return; } diff --git a/src/nanoFramework.Graphics/Graphics/Displays/Spi_To_Display.cpp b/src/nanoFramework.Graphics/Graphics/Displays/Spi_To_Display.cpp index 73cb34ff6d..22eabd4119 100644 --- a/src/nanoFramework.Graphics/Graphics/Displays/Spi_To_Display.cpp +++ b/src/nanoFramework.Graphics/Graphics/Displays/Spi_To_Display.cpp @@ -1,4 +1,4 @@ -// +// // Copyright (c) .NET Foundation and Contributors // See LICENSE file in the project root for full license information. // @@ -307,6 +307,65 @@ void DisplayInterface::SendData16Windowed( return; } +void DisplayInterface::SendData18Windowed( + CLR_UINT16 *data, + CLR_UINT32 startX, + CLR_UINT32 startY, + CLR_UINT32 width, + CLR_UINT32 height, + CLR_UINT32 stride) +{ + // Offset for window start + CLR_UINT16 *startOfLine = data + (startY * stride) + startX; + + CLR_UINT8 *byteBuffer = (CLR_UINT8 *)currentBuffer; + CLR_UINT32 bytesWritten = 0; + + while (height--) + { + CLR_UINT16 *pixel = startOfLine; + + for (CLR_UINT32 x = 0; x < width; x++) + { + CLR_UINT16 color = *pixel++; + + // Extract RGB565 components and bit-widen to 8-bit + CLR_UINT8 b = color & 0x1F; + CLR_UINT8 g = (color >> 5) & 0x3F; + CLR_UINT8 r = (color >> 11) & 0x1F; + + b = (b << 3) | (b >> 2); + g = (g << 2) | (g >> 4); + r = (r << 3) | (r >> 2); + + // Ensure there is room for a full pixel + if (bytesWritten + 3 > SPI_MAX_TRANSFER_SIZE) + { + InternalSendBytes((CLR_UINT8 *)currentBuffer, bytesWritten, true); + SwapBuffers(); + byteBuffer = (CLR_UINT8 *)currentBuffer; + bytesWritten = 0; + } + + byteBuffer[bytesWritten++] = b; + byteBuffer[bytesWritten++] = g; + byteBuffer[bytesWritten++] = r; + } + + startOfLine += stride; + } + + // Flush remaining bytes + if (bytesWritten > 0) + { + InternalSendBytes((CLR_UINT8 *)currentBuffer, bytesWritten, true); + + SwapBuffers(); + } + + return; +} + void DisplayInterface::FillData16(CLR_UINT16 fillValue, CLR_UINT32 fillLength) { // Fill the current buffer full of fillValue, or as much as we need