reactos/dll/opengl/opengl32/swimpl.c

1567 lines
72 KiB
C
Raw Normal View History

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS
* FILE: dll/opengl/opengl32/swimpl.c
* PURPOSE: OpenGL32 DLL, opengl software implementation
*/
#include "opengl32.h"
/* MESA includes */
#include <context.h>
#include <matrix.h>
WINE_DEFAULT_DEBUG_CHANNEL(opengl32);
#define WIDTH_BYTES_ALIGN32(cx, bpp) ((((cx) * (bpp) + 31) & ~31) >> 3)
#define WIDTH_BYTES_ALIGN16(cx, bpp) ((((cx) * (bpp) + 15) & ~15) >> 3)
/* Flags for our pixel formats */
#define SB_FLAGS (PFD_DRAW_TO_BITMAP | PFD_SUPPORT_GDI | PFD_SUPPORT_OPENGL | PFD_GENERIC_FORMAT)
#define SB_FLAGS_WINDOW (PFD_DRAW_TO_BITMAP | PFD_SUPPORT_GDI | PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_GENERIC_FORMAT)
#define SB_FLAGS_PALETTE (PFD_DRAW_TO_BITMAP | PFD_SUPPORT_GDI | PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_GENERIC_FORMAT | PFD_NEED_PALETTE)
#define DB_FLAGS (PFD_DOUBLEBUFFER | PFD_SWAP_COPY | PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_GENERIC_FORMAT)
#define DB_FLAGS_PALETTE (PFD_DOUBLEBUFFER | PFD_SWAP_COPY | PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_GENERIC_FORMAT | PFD_NEED_PALETTE)
struct pixel_format
{
DWORD dwFlags;
BYTE iPixelType;
BYTE cColorBits;
BYTE cRedBits; BYTE cRedShift;
BYTE cGreenBits; BYTE cGreenShift;
BYTE cBlueBits; BYTE cBlueShift;
BYTE cAlphaBits; BYTE cAlphaShift;
BYTE cAccumBits;
BYTE cAccumRedBits; BYTE cAccumGreenBits; BYTE cAccumBlueBits; BYTE cAccumAlphaBits;
BYTE cDepthBits;
};
static const struct pixel_format pixel_formats_32[] =
{
/* 32bpp */
{SB_FLAGS_WINDOW, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 0, 0, 64, 16, 16, 16, 0, 32},
{SB_FLAGS_WINDOW, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 0, 0, 64, 16, 16, 16, 0, 16},
{DB_FLAGS, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 0, 0, 64, 16, 16, 16, 0, 32},
{DB_FLAGS, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 0, 0, 64, 16, 16, 16, 0, 16},
{SB_FLAGS_WINDOW, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 8, 0, 64, 16, 16, 16, 16, 32},
{SB_FLAGS_WINDOW, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 8, 0, 64, 16, 16, 16, 16, 16},
{DB_FLAGS, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 8, 0, 64, 16, 16, 16, 16, 32},
{DB_FLAGS, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 8, 0, 64, 16, 16, 16, 16, 16},
{SB_FLAGS_WINDOW, PFD_TYPE_COLORINDEX, 32, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 32},
{SB_FLAGS_WINDOW, PFD_TYPE_COLORINDEX, 32, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 16},
{DB_FLAGS, PFD_TYPE_COLORINDEX, 32, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 32},
{DB_FLAGS, PFD_TYPE_COLORINDEX, 32, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 16},
/* 24bpp */
{SB_FLAGS, PFD_TYPE_RGBA, 24, 8, 16, 8, 8, 8, 0, 0, 0, 64, 16, 16, 16, 0, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 24, 8, 16, 8, 8, 8, 0, 0, 0, 64, 16, 16, 16, 0, 16},
{SB_FLAGS, PFD_TYPE_RGBA, 24, 8, 16, 8, 8, 8, 0, 8, 0, 64, 16, 16, 16, 16, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 24, 8, 16, 8, 8, 8, 0, 8, 0, 64, 16, 16, 16, 16, 16},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 24, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 32},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 24, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 16},
/* 16 bpp */
{SB_FLAGS, PFD_TYPE_RGBA, 16, 5, 10, 5, 5, 5, 0, 0, 0, 32, 11, 11, 10, 0, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 16, 5, 10, 5, 5, 5, 0, 0, 0, 32, 11, 11, 10, 0, 16},
{SB_FLAGS, PFD_TYPE_RGBA, 16, 5, 10, 5, 5, 5, 0, 8, 0, 32, 8, 8, 8, 8, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 16, 5, 10, 5, 5, 5, 0, 8, 0, 32, 8, 8, 8, 8, 16},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 16, 5, 10, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 32},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 16, 5, 10, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 16},
/* 8bpp */
{SB_FLAGS, PFD_TYPE_RGBA, 8, 3, 0, 3, 3, 2, 6, 0, 0, 32, 11, 11, 10, 0, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 8, 3, 0, 3, 3, 2, 6, 0, 0, 32, 11, 11, 10, 0, 16},
{SB_FLAGS, PFD_TYPE_RGBA, 8, 3, 0, 3, 3, 2, 6, 8, 0, 32, 8, 8, 8, 8, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 8, 3, 0, 3, 3, 2, 6, 8, 0, 32, 8, 8, 8, 8, 16},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 8, 3, 0, 3, 3, 2, 6, 0, 0, 0, 0, 0, 0, 0, 32},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 8, 3, 0, 3, 3, 2, 6, 0, 0, 0, 0, 0, 0, 0, 16},
/* 4bpp */
{SB_FLAGS, PFD_TYPE_RGBA, 4, 1, 0, 1, 1, 1, 2, 0, 0, 16, 5, 6, 5, 0, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 4, 1, 0, 1, 1, 1, 2, 0, 0, 16, 5, 6, 5, 0, 16},
{SB_FLAGS, PFD_TYPE_RGBA, 4, 1, 0, 1, 1, 1, 2, 8, 0, 16, 4, 4, 4, 4, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 4, 1, 0, 1, 1, 1, 2, 8, 0, 16, 4, 4, 4, 4, 16},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 4, 1, 0, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 32},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 4, 1, 0, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 16},
};
static const struct pixel_format pixel_formats_24[] =
{
/* 24bpp */
{SB_FLAGS_WINDOW, PFD_TYPE_RGBA, 24, 8, 16, 8, 8, 8, 0, 0, 0, 64, 16, 16, 16, 0, 32},
{SB_FLAGS_WINDOW, PFD_TYPE_RGBA, 24, 8, 16, 8, 8, 8, 0, 0, 0, 64, 16, 16, 16, 0, 16},
{DB_FLAGS, PFD_TYPE_RGBA, 24, 8, 16, 8, 8, 8, 0, 0, 0, 64, 16, 16, 16, 0, 32},
{DB_FLAGS, PFD_TYPE_RGBA, 24, 8, 16, 8, 8, 8, 0, 0, 0, 64, 16, 16, 16, 0, 16},
{SB_FLAGS_WINDOW, PFD_TYPE_RGBA, 24, 8, 16, 8, 8, 8, 0, 8, 0, 64, 16, 16, 16, 16, 32},
{SB_FLAGS_WINDOW, PFD_TYPE_RGBA, 24, 8, 16, 8, 8, 8, 0, 8, 0, 64, 16, 16, 16, 16, 16},
{DB_FLAGS, PFD_TYPE_RGBA, 24, 8, 16, 8, 8, 8, 0, 8, 0, 64, 16, 16, 16, 16, 32},
{DB_FLAGS, PFD_TYPE_RGBA, 24, 8, 16, 8, 8, 8, 0, 8, 0, 64, 16, 16, 16, 16, 16},
{SB_FLAGS_WINDOW, PFD_TYPE_COLORINDEX, 24, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 32},
{SB_FLAGS_WINDOW, PFD_TYPE_COLORINDEX, 24, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 16},
{DB_FLAGS, PFD_TYPE_COLORINDEX, 24, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 32},
{DB_FLAGS, PFD_TYPE_COLORINDEX, 24, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 16},
/* 32bpp */
{SB_FLAGS, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 0, 0, 64, 16, 16, 16, 0, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 0, 0, 64, 16, 16, 16, 0, 16},
{SB_FLAGS, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 8, 0, 64, 16, 16, 16, 16, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 8, 0, 64, 16, 16, 16, 16, 16},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 32, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 32},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 32, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 16},
/* 16 bpp */
{SB_FLAGS, PFD_TYPE_RGBA, 16, 5, 10, 5, 5, 5, 0, 0, 0, 32, 11, 11, 10, 0, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 16, 5, 10, 5, 5, 5, 0, 0, 0, 32, 11, 11, 10, 0, 16},
{SB_FLAGS, PFD_TYPE_RGBA, 16, 5, 10, 5, 5, 5, 0, 8, 0, 32, 8, 8, 8, 8, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 16, 5, 10, 5, 5, 5, 0, 8, 0, 32, 8, 8, 8, 8, 16},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 16, 5, 10, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 32},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 16, 5, 10, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 16},
/* 8bpp */
{SB_FLAGS, PFD_TYPE_RGBA, 8, 3, 0, 3, 3, 2, 6, 0, 0, 32, 11, 11, 10, 0, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 8, 3, 0, 3, 3, 2, 6, 0, 0, 32, 11, 11, 10, 0, 16},
{SB_FLAGS, PFD_TYPE_RGBA, 8, 3, 0, 3, 3, 2, 6, 8, 0, 32, 8, 8, 8, 8, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 8, 3, 0, 3, 3, 2, 6, 8, 0, 32, 8, 8, 8, 8, 16},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 8, 3, 0, 3, 3, 2, 6, 0, 0, 0, 0, 0, 0, 0, 32},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 8, 3, 0, 3, 3, 2, 6, 0, 0, 0, 0, 0, 0, 0, 16},
/* 4bpp */
{SB_FLAGS, PFD_TYPE_RGBA, 4, 1, 0, 1, 1, 1, 2, 0, 0, 16, 5, 6, 5, 0, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 4, 1, 0, 1, 1, 1, 2, 0, 0, 16, 5, 6, 5, 0, 16},
{SB_FLAGS, PFD_TYPE_RGBA, 4, 1, 0, 1, 1, 1, 2, 8, 0, 16, 4, 4, 4, 4, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 4, 1, 0, 1, 1, 1, 2, 8, 0, 16, 4, 4, 4, 4, 16},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 4, 1, 0, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 32},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 4, 1, 0, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 16},
};
static const struct pixel_format pixel_formats_16[] =
{
/* 16 bpp - 565 */
{SB_FLAGS_WINDOW, PFD_TYPE_RGBA, 16, 5, 11, 6, 5, 5, 0, 0, 0, 32, 11, 11, 10, 0, 32},
{SB_FLAGS_WINDOW, PFD_TYPE_RGBA, 16, 5, 11, 6, 5, 5, 0, 0, 0, 32, 11, 11, 10, 0, 16},
{DB_FLAGS, PFD_TYPE_RGBA, 16, 5, 11, 6, 5, 5, 0, 0, 0, 32, 11, 11, 10, 0, 32},
{DB_FLAGS, PFD_TYPE_RGBA, 16, 5, 11, 6, 5, 5, 0, 0, 0, 32, 11, 11, 10, 0, 16},
{SB_FLAGS_WINDOW, PFD_TYPE_RGBA, 16, 5, 11, 6, 5, 5, 0, 8, 0, 32, 8, 8, 8, 8, 32},
{SB_FLAGS_WINDOW, PFD_TYPE_RGBA, 16, 5, 11, 6, 5, 5, 0, 8, 0, 32, 8, 8, 8, 8, 16},
{DB_FLAGS, PFD_TYPE_RGBA, 16, 5, 11, 6, 5, 5, 0, 8, 0, 32, 8, 8, 8, 8, 32},
{DB_FLAGS, PFD_TYPE_RGBA, 16, 5, 11, 6, 5, 5, 0, 8, 0, 32, 8, 8, 8, 8, 16},
{SB_FLAGS_WINDOW, PFD_TYPE_COLORINDEX, 16, 5, 11, 6, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 32},
{SB_FLAGS_WINDOW, PFD_TYPE_COLORINDEX, 16, 5, 11, 6, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 16},
{DB_FLAGS, PFD_TYPE_COLORINDEX, 16, 5, 11, 6, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 32},
{DB_FLAGS, PFD_TYPE_COLORINDEX, 16, 5, 11, 6, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 16},
/* 24bpp */
{SB_FLAGS, PFD_TYPE_RGBA, 24, 8, 16, 8, 8, 8, 0, 0, 0, 64, 16, 16, 16, 0, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 24, 8, 16, 8, 8, 8, 0, 0, 0, 64, 16, 16, 16, 0, 16},
{SB_FLAGS, PFD_TYPE_RGBA, 24, 8, 16, 8, 8, 8, 0, 8, 0, 64, 16, 16, 16, 16, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 24, 8, 16, 8, 8, 8, 0, 8, 0, 64, 16, 16, 16, 16, 16},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 24, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 32},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 24, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 16},
/* 32bpp */
{SB_FLAGS, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 0, 0, 64, 16, 16, 16, 0, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 0, 0, 64, 16, 16, 16, 0, 16},
{SB_FLAGS, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 8, 0, 64, 16, 16, 16, 16, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 8, 0, 64, 16, 16, 16, 16, 16},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 32, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 32},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 32, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 16},
/* 8bpp */
{SB_FLAGS, PFD_TYPE_RGBA, 8, 3, 0, 3, 3, 2, 6, 0, 0, 32, 11, 11, 10, 0, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 8, 3, 0, 3, 3, 2, 6, 0, 0, 32, 11, 11, 10, 0, 16},
{SB_FLAGS, PFD_TYPE_RGBA, 8, 3, 0, 3, 3, 2, 6, 8, 0, 32, 8, 8, 8, 8, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 8, 3, 0, 3, 3, 2, 6, 8, 0, 32, 8, 8, 8, 8, 16},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 8, 3, 0, 3, 3, 2, 6, 0, 0, 0, 0, 0, 0, 0, 32},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 8, 3, 0, 3, 3, 2, 6, 0, 0, 0, 0, 0, 0, 0, 16},
/* 4bpp */
{SB_FLAGS, PFD_TYPE_RGBA, 4, 1, 0, 1, 1, 1, 2, 0, 0, 16, 5, 6, 5, 0, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 4, 1, 0, 1, 1, 1, 2, 0, 0, 16, 5, 6, 5, 0, 16},
{SB_FLAGS, PFD_TYPE_RGBA, 4, 1, 0, 1, 1, 1, 2, 8, 0, 16, 4, 4, 4, 4, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 4, 1, 0, 1, 1, 1, 2, 8, 0, 16, 4, 4, 4, 4, 16},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 4, 1, 0, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 32},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 4, 1, 0, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 16},
};
static const struct pixel_format pixel_formats_8[] =
{
/* 8bpp */
{SB_FLAGS_PALETTE, PFD_TYPE_RGBA, 8, 3, 0, 3, 3, 2, 6, 0, 0, 32, 11, 11, 10, 0, 32},
{SB_FLAGS_PALETTE, PFD_TYPE_RGBA, 8, 3, 0, 3, 3, 2, 6, 0, 0, 32, 11, 11, 10, 0, 16},
{DB_FLAGS_PALETTE, PFD_TYPE_RGBA, 8, 3, 0, 3, 3, 2, 6, 0, 0, 32, 11, 11, 10, 0, 32},
{DB_FLAGS_PALETTE, PFD_TYPE_RGBA, 8, 3, 0, 3, 3, 2, 6, 0, 0, 32, 11, 11, 10, 0, 16},
{SB_FLAGS_PALETTE, PFD_TYPE_RGBA, 8, 3, 0, 3, 3, 2, 6, 8, 0, 32, 8, 8, 8, 8, 32},
{SB_FLAGS_PALETTE, PFD_TYPE_RGBA, 8, 3, 0, 3, 3, 2, 6, 8, 0, 32, 8, 8, 8, 8, 16},
{DB_FLAGS_PALETTE, PFD_TYPE_RGBA, 8, 3, 0, 3, 3, 2, 6, 8, 0, 32, 8, 8, 8, 8, 32},
{DB_FLAGS_PALETTE, PFD_TYPE_RGBA, 8, 3, 0, 3, 3, 2, 6, 8, 0, 32, 8, 8, 8, 8, 16},
{SB_FLAGS_WINDOW, PFD_TYPE_COLORINDEX, 8, 3, 0, 3, 3, 2, 6, 0, 0, 0, 0, 0, 0, 0, 32},
{SB_FLAGS_WINDOW, PFD_TYPE_COLORINDEX, 8, 3, 0, 3, 3, 2, 6, 0, 0, 0, 0, 0, 0, 0, 16},
{DB_FLAGS, PFD_TYPE_COLORINDEX, 8, 3, 0, 3, 3, 2, 6, 0, 0, 0, 0, 0, 0, 0, 32},
{DB_FLAGS, PFD_TYPE_COLORINDEX, 8, 3, 0, 3, 3, 2, 6, 0, 0, 0, 0, 0, 0, 0, 16},
/* 24bpp */
{SB_FLAGS, PFD_TYPE_RGBA, 24, 8, 16, 8, 8, 8, 0, 0, 0, 64, 16, 16, 16, 0, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 24, 8, 16, 8, 8, 8, 0, 0, 0, 64, 16, 16, 16, 0, 16},
{SB_FLAGS, PFD_TYPE_RGBA, 24, 8, 16, 8, 8, 8, 0, 8, 0, 64, 16, 16, 16, 16, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 24, 8, 16, 8, 8, 8, 0, 8, 0, 64, 16, 16, 16, 16, 16},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 24, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 32},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 24, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 16},
/* 32bpp */
{SB_FLAGS, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 0, 0, 64, 16, 16, 16, 0, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 0, 0, 64, 16, 16, 16, 0, 16},
{SB_FLAGS, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 8, 0, 64, 16, 16, 16, 16, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 8, 0, 64, 16, 16, 16, 16, 16},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 32, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 32},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 32, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 16},
/* 16 bpp */
{SB_FLAGS, PFD_TYPE_RGBA, 16, 5, 10, 5, 5, 5, 0, 0, 0, 32, 11, 11, 10, 0, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 16, 5, 10, 5, 5, 5, 0, 0, 0, 32, 11, 11, 10, 0, 16},
{SB_FLAGS, PFD_TYPE_RGBA, 16, 5, 10, 5, 5, 5, 0, 8, 0, 32, 8, 8, 8, 8, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 16, 5, 10, 5, 5, 5, 0, 8, 0, 32, 8, 8, 8, 8, 16},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 16, 5, 10, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 32},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 16, 5, 10, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 16},
/* 4bpp */
{SB_FLAGS, PFD_TYPE_RGBA, 4, 1, 0, 1, 1, 1, 2, 0, 0, 16, 5, 6, 5, 0, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 4, 1, 0, 1, 1, 1, 2, 0, 0, 16, 5, 6, 5, 0, 16},
{SB_FLAGS, PFD_TYPE_RGBA, 4, 1, 0, 1, 1, 1, 2, 8, 0, 16, 4, 4, 4, 4, 32},
{SB_FLAGS, PFD_TYPE_RGBA, 4, 1, 0, 1, 1, 1, 2, 8, 0, 16, 4, 4, 4, 4, 16},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 4, 1, 0, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 32},
{SB_FLAGS, PFD_TYPE_COLORINDEX, 4, 1, 0, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 16},
};
struct sw_framebuffer
{
GLvisual *gl_visual; /* Describes the buffers */
GLframebuffer *gl_buffer; /* Depth, stencil, accum, etc buffers */
const struct pixel_format* pixel_format;
HDC Hdc;
/* Current width/height */
GLuint width; GLuint height;
/* BackBuffer, if any */
BYTE* BackBuffer;
};
struct sw_context
{
GLcontext *gl_ctx; /* The core GL/Mesa context */
/* This is to keep track of the size of the front buffer */
HHOOK hook;
/* Our frame buffer*/
struct sw_framebuffer* fb;
/* State variables */
union
{
struct
{
BYTE ClearColor;
BYTE CurrentColor;
} u8;
struct
{
USHORT ClearColor;
USHORT CurrentColor;
} u16;
struct
{
ULONG ClearColor;
ULONG CurrentColor;
} u24;
struct
{
ULONG ClearColor;
ULONG CurrentColor;
} u32;
};
GLenum Mode;
};
/* WGL <-> mesa glue */
static const struct pixel_format* get_format(INT pf_index, INT* pf_count)
{
HDC hdc;
INT bpp, nb_format;
const struct pixel_format* ret;
hdc = GetDC(NULL);
bpp = GetDeviceCaps(hdc, BITSPIXEL);
ReleaseDC(NULL, hdc);
switch (bpp)
{
#define HANDLE_BPP(__x__) \
case __x__: \
nb_format = ARRAYSIZE(pixel_formats_##__x__); \
if ((pf_index > nb_format) || (pf_index <= 0)) \
ret = NULL; \
else \
ret = &pixel_formats_##__x__[pf_index - 1]; \
break
HANDLE_BPP(32);
HANDLE_BPP(24);
HANDLE_BPP(16);
HANDLE_BPP(8);
#undef HANDLE_BPP
default:
FIXME("Unhandled bit depth %u, defaulting to 32bpp\n", bpp);
nb_format = ARRAYSIZE(pixel_formats_32);
if ((pf_index > nb_format) || (pf_index == 0))
ret = NULL;
else
ret = &pixel_formats_32[pf_index - 1];
}
if (pf_count)
*pf_count = nb_format;
return ret;
}
INT sw_DescribePixelFormat(HDC hdc, INT format, UINT size, PIXELFORMATDESCRIPTOR* descr)
{
INT ret;
const struct pixel_format *pixel_format;
TRACE("Describing format %i.\n", format);
pixel_format = get_format(format, &ret);
if(!descr)
return ret;
if((format > ret) || (size != sizeof(*descr)))
return 0;
/* Fill the structure */
descr->nSize = sizeof(*descr);
descr->nVersion = 1;
descr->dwFlags = pixel_format->dwFlags;
descr->iPixelType = pixel_format->iPixelType;
descr->cColorBits = pixel_format->cColorBits;
descr->cRedBits = pixel_format->cRedBits;
descr->cRedShift = pixel_format->cRedShift;
descr->cGreenBits = pixel_format->cGreenBits;
descr->cGreenShift = pixel_format->cGreenShift;
descr->cBlueBits = pixel_format->cBlueBits;
descr->cBlueShift = pixel_format->cBlueShift;
descr->cAlphaBits = pixel_format->cAlphaBits;
descr->cAlphaShift = pixel_format->cAlphaShift;
descr->cAccumBits = pixel_format->cAccumBits;
descr->cAccumRedBits = pixel_format->cAccumRedBits;
descr->cAccumGreenBits = pixel_format->cAccumGreenBits;
descr->cAccumBlueBits = pixel_format->cAccumBlueBits;
descr->cAccumAlphaBits = pixel_format->cAccumAlphaBits;
descr->cDepthBits = pixel_format->cDepthBits;
descr->cStencilBits = STENCIL_BITS;
descr->cAuxBuffers = 0;
descr->iLayerType = PFD_MAIN_PLANE;
descr->bReserved = 0;
descr->dwLayerMask = 0;
descr->dwVisibleMask = 0;
descr->dwDamageMask = 0;
return ret;
}
BOOL sw_SetPixelFormat(HDC hdc, struct wgl_dc_data* dc_data, INT format)
{
struct sw_framebuffer* fb;
const struct pixel_format *pixel_format;
/* So, someone is crazy enough to ask for sw implementation. Announce it. */
TRACE("OpenGL software implementation START for hdc %p, format %i!\n", hdc, format);
pixel_format = get_format(format, NULL);
if (!pixel_format)
return FALSE;
/* allocate our structure */
fb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*fb));
if(!fb)
{
ERR("HeapAlloc FAILED!\n");
return FALSE;
}
/* Set the format */
fb->pixel_format = pixel_format;
fb->gl_visual = gl_create_visual(
pixel_format->iPixelType == PFD_TYPE_RGBA,
pixel_format->cAlphaBits != 0,
(pixel_format->dwFlags & PFD_DOUBLEBUFFER) != 0,
pixel_format->cDepthBits,
STENCIL_BITS,
max(max(max(pixel_format->cAccumRedBits, pixel_format->cAccumGreenBits), pixel_format->cAccumBlueBits), pixel_format->cAccumAlphaBits),
pixel_format->iPixelType == PFD_TYPE_COLORINDEX ? pixel_format->cColorBits : 0,
((1ul << pixel_format->cRedBits) - 1),
((1ul << pixel_format->cGreenBits) - 1),
((1ul << pixel_format->cBlueBits) - 1),
pixel_format->cAlphaBits != 0 ? ((1ul << pixel_format->cAlphaBits) - 1) : 255.0f,
pixel_format->cRedBits,
pixel_format->cGreenBits,
pixel_format->cBlueBits,
pixel_format->cAlphaBits);
if(!fb->gl_visual)
{
ERR("Failed to allocate a GL visual.\n");
HeapFree(GetProcessHeap(), 0, fb);
return FALSE;
}
/* Allocate the framebuffer structure */
fb->gl_buffer = gl_create_framebuffer(fb->gl_visual);
if (!fb->gl_buffer) {
ERR("Failed to allocate the mesa framebuffer structure.\n");
gl_destroy_visual( fb->gl_visual );
HeapFree(GetProcessHeap(), 0, fb);
return FALSE;
}
/* Save our DC */
fb->Hdc = hdc;
/* Everything went fine */
dc_data->sw_data = fb;
return TRUE;
}
DHGLRC sw_CreateContext(struct wgl_dc_data* dc_data)
{
struct sw_context* sw_ctx;
struct sw_framebuffer* fb = dc_data->sw_data;
sw_ctx = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*sw_ctx));
if(!sw_ctx)
return NULL;
/* Initialize the context */
sw_ctx->gl_ctx = gl_create_context(fb->gl_visual, NULL, sw_ctx);
if(!sw_ctx->gl_ctx)
{
ERR("Failed to initialize the mesa context.\n");
HeapFree(GetProcessHeap(), 0, sw_ctx);
return NULL;
}
sw_ctx->fb = fb;
/* Choose relevant default */
sw_ctx->Mode = fb->gl_visual->DBflag ? GL_BACK : GL_FRONT;
return (DHGLRC)sw_ctx;
}
BOOL sw_DeleteContext(DHGLRC dhglrc)
{
struct sw_context* sw_ctx = (struct sw_context*)dhglrc;
/* Those get clobbered by _mesa_free_context_data via _glapi_set{context,dispath_table} */
void* icd_save = IntGetCurrentICDPrivate();
const GLDISPATCHTABLE* table_save = IntGetCurrentDispatchTable();
/* Destroy everything */
gl_destroy_context(sw_ctx->gl_ctx);
HeapFree(GetProcessHeap(), 0, sw_ctx);
/* Restore this */
IntSetCurrentDispatchTable(table_save);
IntSetCurrentICDPrivate(icd_save);
return TRUE;
}
extern void APIENTRY _mesa_ColorTableEXT(GLenum, GLenum, GLsizei, GLenum, GLenum, const void*);
extern void APIENTRY _mesa_ColorSubTableEXT(GLenum, GLsizei, GLsizei, GLenum, GLenum, const void*);
extern void APIENTRY _mesa_GetColorTableEXT(GLenum, GLenum, GLenum, void*);
extern void APIENTRY _mesa_GetColorTableParameterivEXT(GLenum, GLenum, GLfloat*);
extern void APIENTRY _mesa_GetColorTableParameterfvEXT(GLenum, GLenum, GLint*);
static void APIENTRY _swimpl_AddSwapHintRectWIN(GLint x, GLint y, GLsizei width, GLsizei height)
{
UNIMPLEMENTED;
}
PROC sw_GetProcAddress(LPCSTR name)
{
/* GL_EXT_paletted_texture */
if (strcmp(name, "glColorTableEXT") == 0)
return (PROC)_mesa_ColorTableEXT;
if (strcmp(name, "glColorSubTableEXT") == 0)
return (PROC)_mesa_ColorSubTableEXT;
if (strcmp(name, "glColorGetTableEXT") == 0)
return (PROC)_mesa_GetColorTableEXT;
if (strcmp(name, "glGetColorTableParameterivEXT") == 0)
return (PROC)_mesa_GetColorTableParameterivEXT;
if (strcmp(name, "glGetColorTableParameterfvEXT") == 0)
return (PROC)_mesa_GetColorTableParameterfvEXT;
if (strcmp(name, "glAddSwapHintRectWIN") == 0)
return (PROC)_swimpl_AddSwapHintRectWIN;
WARN("Asking for proc address %s, returning NULL.\n", name);
return NULL;
}
BOOL sw_CopyContext(DHGLRC dhglrcSrc, DHGLRC dhglrcDst, UINT mask)
{
FIXME("Software wglCopyContext is UNIMPLEMENTED, mask %lx.\n", mask);
return FALSE;
}
BOOL sw_ShareLists(DHGLRC dhglrcSrc, DHGLRC dhglrcDst)
{
#if 0
struct sw_context* sw_ctx_src = (struct sw_context*)dhglrcSrc;
struct sw_context* sw_ctx_dst = (struct sw_context*)dhglrcDst;
/* See if it was already shared */
if(sw_ctx_dst->gl_ctx->Shared->RefCount > 1)
return FALSE;
/* Unreference the old, share the new */
gl_reference_shared_state(sw_ctx_dst->gl_ctx,
&sw_ctx_dst->gl_ctx->Shared,
sw_ctx_src->gl_ctx->Shared);
#endif
FIXME("Unimplemented!\n");
return TRUE;
}
static
LRESULT CALLBACK
sw_call_window_proc(
int nCode,
WPARAM wParam,
LPARAM lParam )
{
struct wgl_dc_data* dc_data = IntGetCurrentDcData();
struct sw_context* ctx = (struct sw_context*)IntGetCurrentDHGLRC();
PCWPSTRUCT pParams = (PCWPSTRUCT)lParam;
if((!dc_data) || (!ctx))
return 0;
if(!(dc_data->flags & WGL_DC_OBJ_DC))
return 0;
if((nCode < 0) || (dc_data->owner.hwnd != pParams->hwnd) || (dc_data->sw_data == NULL))
return CallNextHookEx(ctx->hook, nCode, wParam, lParam);
if (pParams->message == WM_WINDOWPOSCHANGED)
{
/* We handle WM_WINDOWPOSCHANGED instead of WM_SIZE because according to
* http://blogs.msdn.com/oldnewthing/archive/2008/01/15/7113860.aspx
* WM_SIZE is generated from WM_WINDOWPOSCHANGED by DefWindowProc so it
* can be masked out by the application. */
LPWINDOWPOS lpWindowPos = (LPWINDOWPOS)pParams->lParam;
if((lpWindowPos->flags & SWP_SHOWWINDOW) ||
!(lpWindowPos->flags & SWP_NOMOVE) ||
!(lpWindowPos->flags & SWP_NOSIZE))
{
/* Size in WINDOWPOS includes the window frame, so get the size
* of the client area via GetClientRect. */
RECT client_rect;
UINT width, height;
TRACE("Got WM_WINDOWPOSCHANGED\n");
GetClientRect(pParams->hwnd, &client_rect);
width = client_rect.right - client_rect.left;
height = client_rect.bottom - client_rect.top;
/* Do not reallocate for minimized windows */
if(width <= 0 || height <= 0)
goto end;
/* Propagate to mesa */
gl_ResizeBuffersMESA(ctx->gl_ctx);
}
}
end:
return CallNextHookEx(ctx->hook, nCode, wParam, lParam);
}
static const char* renderer_string(void)
{
return "ReactOS SW Implementation";
}
static inline void PUT_PIXEL_8(BYTE* Buffer, BYTE Value)
{
*Buffer = Value;
}
static inline void PUT_PIXEL_16(USHORT* Buffer, USHORT Value)
{
*Buffer = Value;
}
static inline void PUT_PIXEL_24(ULONG* Buffer, ULONG Value)
{
*Buffer &= 0xFF000000ul;
*Buffer |= Value & 0x00FFFFFF;
}
static inline void PUT_PIXEL_32(ULONG* Buffer, ULONG Value)
{
*Buffer = Value;
}
static inline BYTE GET_PIXEL_8(BYTE* Buffer)
{
return *Buffer;
}
static inline USHORT GET_PIXEL_16(USHORT* Buffer)
{
return *Buffer;
}
static inline ULONG GET_PIXEL_24(ULONG* Buffer)
{
return *Buffer & 0x00FFFFFF;
}
static inline ULONG GET_PIXEL_32(ULONG* Buffer)
{
return *Buffer;
}
static inline COLORREF MAKE_COLORREF_8(const struct pixel_format *format, BYTE Color)
{
BYTE R,G,B;
if (format->iPixelType == PFD_TYPE_COLORINDEX)
return PALETTEINDEX(Color);
R = (Color & 0x7) << 5;
G = (Color & 0x38) << 2;
B = Color & 0xC;
return RGB(R, G, B);
}
static inline COLORREF MAKE_COLORREF_16(const struct pixel_format *format, USHORT Color)
{
BYTE R,G,B;
if (format->iPixelType == PFD_TYPE_COLORINDEX)
return PALETTEINDEX(Color);
R = (Color & 0x7) << 5;
G = (Color & 0x38) << 2;
B = Color & 0xC;
return RGB(R, G, B);
}
static inline COLORREF MAKE_COLORREF_24(const struct pixel_format *format, ULONG Color)
{
BYTE R,G,B;
if (format->iPixelType == PFD_TYPE_COLORINDEX)
return PALETTEINDEX(Color);
R = (Color & 0xFF0000) >> 16;
G = (Color & 0x00FF00) >> 8;
B = Color & 0xFF;
return RGB(R, G, B);
}
static inline COLORREF MAKE_COLORREF_32(const struct pixel_format *format, ULONG Color)
{
BYTE R,G,B;
if (format->iPixelType == PFD_TYPE_COLORINDEX)
return PALETTEINDEX(Color);
R = (Color & 0xFF0000) >> 16;
G = (Color & 0x00FF00) >> 8;
B = Color & 0xFF;
return RGB(R, G, B);
}
static inline BYTE PACK_COLOR_8(GLubyte r, GLubyte g, GLubyte b)
{
return (r & 0x7) | ((g & 0x7) << 3) | ((b & 0x3) << 6);
}
static inline USHORT PACK_COLOR_16(GLubyte r, GLubyte g, GLubyte b)
{
return ((r & 0x1F) << 11) | ((g & 0x3F) << 5) | (b & 0x1F);
}
static inline ULONG PACK_COLOR_24(GLubyte r, GLubyte g, GLubyte b)
{
return (r << 16) | (g << 8) | (b);
}
static inline ULONG PACK_COLOR_32(GLubyte r, GLubyte g, GLubyte b)
{
return (r << 16) | (g << 8) | (b);
}
static inline COLORREF PACK_COLORREF_8(GLubyte r, GLubyte g, GLubyte b)
{
return RGB(r << 5, g << 5, b << 6);
}
static inline COLORREF PACK_COLORREF_16(GLubyte r, GLubyte g, GLubyte b)
{
return RGB(r << 3, g << 2, b << 3);
}
static inline COLORREF PACK_COLORREF_24(GLubyte r, GLubyte g, GLubyte b)
{
return RGB(r, g, b);
}
static inline COLORREF PACK_COLORREF_32(GLubyte r, GLubyte g, GLubyte b)
{
return RGB(r, g, b);
}
static inline void UNPACK_COLOR_8(BYTE Color, GLubyte* r, GLubyte* g, GLubyte* b)
{
*r = Color & 0x7;
*g = (Color >> 3) & 0x7;
*b = (Color >> 6) & 0x3;
}
static inline void UNPACK_COLOR_16(USHORT Color, GLubyte* r, GLubyte* g, GLubyte* b)
{
*r = (Color >> 11) & 0x1F;
*g = (Color >> 5) & 0x3F;
*b = Color & 0x1F;
}
static inline void UNPACK_COLOR_24(ULONG Color, GLubyte* r, GLubyte* g, GLubyte* b)
{
*r = (Color >> 16) & 0xFF;
*g = (Color >> 8) & 0xFF;
*b = Color & 0xFF;
}
static inline void UNPACK_COLOR_32(ULONG Color, GLubyte* r, GLubyte* g, GLubyte* b)
{
*r = (Color >> 16) & 0xFF;
*g = (Color >> 8) & 0xFF;
*b = Color & 0xFF;
}
static inline void UNPACK_COLORREF_8(COLORREF Color, GLubyte* r, GLubyte* g, GLubyte* b)
{
*r = GetRValue(Color) >> 5;
*g = GetGValue(Color) >> 5;
*b = GetBValue(Color) >> 6;
}
static inline void UNPACK_COLORREF_16(COLORREF Color, GLubyte* r, GLubyte* g, GLubyte* b)
{
*r = GetRValue(Color) >> 3;
*g = GetGValue(Color) >> 2;
*b = GetBValue(Color) >> 3;
}
static inline void UNPACK_COLORREF_24(COLORREF Color, GLubyte* r, GLubyte* g, GLubyte* b)
{
*r = GetRValue(Color);
*g = GetGValue(Color);
*b = GetBValue(Color);
}
static inline void UNPACK_COLORREF_32(COLORREF Color, GLubyte* r, GLubyte* g, GLubyte* b)
{
*r = GetRValue(Color);
*g = GetGValue(Color);
*b = GetBValue(Color);
}
/*
* Set the color index used to clear the color buffer.
*/
#define CLEAR_INDEX(__bpp, __type) \
static void clear_index_##__bpp(GLcontext* ctx, GLuint index) \
{ \
struct sw_context* sw_ctx = ctx->DriverCtx; \
\
sw_ctx->u##__bpp.ClearColor = (__type)index; \
}
CLEAR_INDEX(8, BYTE)
CLEAR_INDEX(16, USHORT)
CLEAR_INDEX(24, ULONG)
CLEAR_INDEX(32, ULONG)
#undef CLEAR_INDEX
/*
* Set the color used to clear the color buffer.
*/
#define CLEAR_COLOR(__bpp) \
static void clear_color_##__bpp( GLcontext* ctx, GLubyte r, GLubyte g, GLubyte b, GLubyte a ) \
{ \
struct sw_context* sw_ctx = ctx->DriverCtx; \
\
sw_ctx->u##__bpp.ClearColor = PACK_COLOR_##__bpp(r, g, b); \
\
TRACE("Set Clear color %u, %u, %u.\n", r, g, b); \
}
CLEAR_COLOR(8)
CLEAR_COLOR(16)
CLEAR_COLOR(24)
CLEAR_COLOR(32)
#undef CLEAR_COLOR
/*
* Clear the specified region of the color buffer using the clear color
* or index as specified by one of the two functions above.
*/
static void clear_frontbuffer(
struct sw_context* sw_ctx,
struct sw_framebuffer* fb,
GLint x,
GLint y,
GLint width,
GLint height,
COLORREF ClearColor)
{
HBRUSH Brush;
BOOL ret;
TRACE("Clearing front buffer (%u, %u, %u, %u), color 0x%08x.\n", x, y, width, height, ClearColor);
Brush = CreateSolidBrush(ClearColor);
Brush = SelectObject(fb->Hdc, Brush);
ret = PatBlt(fb->Hdc, x, fb->height - (y + height), width, height, PATCOPY);
if (!ret)
{
ERR("PatBlt failed. last Error %d.\n", GetLastError());
}
Brush = SelectObject(fb->Hdc, Brush);
DeleteObject(Brush);
}
#define CLEAR(__bpp, __type, __pixel_size) \
static void clear_##__bpp(GLcontext* ctx, GLboolean all,GLint x, GLint y, GLint width, GLint height)\
{ \
struct sw_context* sw_ctx = ctx->DriverCtx; \
struct sw_framebuffer* fb = sw_ctx->fb; \
BYTE* ScanLine; \
\
if (all) \
{ \
x = y = 0; \
width = fb->width; \
height = fb->height; \
} \
\
if (sw_ctx->Mode == GL_FRONT) \
{ \
clear_frontbuffer(sw_ctx, fb, x, y, width, height, \
MAKE_COLORREF_##__bpp(fb->pixel_format, sw_ctx->u##__bpp.ClearColor)); \
return; \
} \
\
ScanLine = fb->BackBuffer + y * WIDTH_BYTES_ALIGN32(fb->width, __bpp); \
while (height--) \
{ \
BYTE* Buffer = ScanLine + x * __pixel_size; \
UINT n = width; \
\
while (n--) \
{ \
PUT_PIXEL_##__bpp((__type*)Buffer, sw_ctx->u##__bpp.ClearColor); \
Buffer += __pixel_size; \
} \
\
ScanLine += WIDTH_BYTES_ALIGN32(fb->width, __bpp); \
} \
}
CLEAR(8, BYTE, 1)
CLEAR(16, USHORT, 2)
CLEAR(24, ULONG, 3)
CLEAR(32, ULONG, 4)
#undef CLEAR
/* Set the current color index. */
#define SET_INDEX(__bpp) \
static void set_index_##__bpp(GLcontext* ctx, GLuint index) \
{ \
struct sw_context* sw_ctx = ctx->DriverCtx; \
\
sw_ctx->u##__bpp.CurrentColor = index; \
}
SET_INDEX(8)
SET_INDEX(16)
SET_INDEX(24)
SET_INDEX(32)
#undef SET_INDEX
/* Set the current RGBA color. */
#define SET_COLOR(__bpp) \
static void set_color_##__bpp( GLcontext* ctx, GLubyte r, GLubyte g, GLubyte b, GLubyte a ) \
{ \
struct sw_context* sw_ctx = ctx->DriverCtx; \
\
sw_ctx->u##__bpp.CurrentColor = PACK_COLOR_##__bpp(r, g, b); \
}
SET_COLOR(8)
SET_COLOR(16)
SET_COLOR(24)
SET_COLOR(32)
#undef SET_COLOR
/*
* Selects either the front or back color buffer for reading and writing.
* mode is either GL_FRONT or GL_BACK.
*/
static GLboolean set_buffer( GLcontext* ctx, GLenum mode )
{
struct sw_context* sw_ctx = ctx->DriverCtx;
struct sw_framebuffer* fb = sw_ctx->fb;
if (!fb->gl_visual->DBflag)
return GL_FALSE;
if ((mode != GL_FRONT) && (mode != GL_BACK))
return GL_FALSE;
sw_ctx->Mode = mode;
return GL_TRUE;
}
/* Return characteristics of the output buffer. */
static void buffer_size(GLcontext* ctx, GLuint *width, GLuint *height)
{
struct sw_context* sw_ctx = ctx->DriverCtx;
struct sw_framebuffer* fb = sw_ctx->fb;
HWND Window = WindowFromDC(fb->Hdc);
if (Window)
{
RECT client_rect;
GetClientRect(Window, &client_rect);
*width = client_rect.right - client_rect.left;
*height = client_rect.bottom - client_rect.top;
}
else
{
/* We are drawing to a bitmap */
BITMAP bm;
HBITMAP Hbm;
Hbm = GetCurrentObject(fb->Hdc, OBJ_BITMAP);
if (!GetObjectW(Hbm, sizeof(bm), &bm))
return;
TRACE("Framebuffer size : %i, %i\n", bm.bmWidth, bm.bmHeight);
*width = bm.bmWidth;
*height = bm.bmHeight;
}
if ((*width != fb->width) || (*height != fb->height))
{
const struct pixel_format* pixel_format = fb->pixel_format;
if (pixel_format->dwFlags & PFD_DOUBLEBUFFER)
{
/* Allocate a new backbuffer */
size_t BufferSize = *height * WIDTH_BYTES_ALIGN32(*width, pixel_format->cColorBits);
if (!fb->BackBuffer)
{
fb->BackBuffer = HeapAlloc(GetProcessHeap(), 0, BufferSize);
}
else
{
fb->BackBuffer = HeapReAlloc(GetProcessHeap(), 0, fb->BackBuffer, BufferSize);
}
if (!fb->BackBuffer)
{
ERR("Failed allocating back buffer !.\n");
return;
}
}
fb->width = *width;
fb->height = *height;
}
}
/* Write a horizontal span of color pixels with a boolean mask. */
#define WRITE_COLOR_SPAN_FRONTBUFFER(__bpp) \
static void write_color_span_frontbuffer_##__bpp(struct sw_framebuffer* fb, \
GLuint n, GLint x, GLint y, \
const GLubyte red[], const GLubyte green[], \
const GLubyte blue[], const GLubyte mask[] ) \
{ \
TRACE("Writing color span at %u, %u (%u)\n", x, y, n); \
\
if (mask) \
{ \
while (n--) \
{ \
if (mask[n]) \
{ \
SetPixel(fb->Hdc, x + n, fb->height - y, \
PACK_COLORREF_##__bpp(red[n], green[n], blue[n])); \
} \
} \
} \
else \
{ \
while (n--) \
{ \
SetPixel(fb->Hdc, x + n, fb->height - y, \
PACK_COLORREF_##__bpp(red[n], green[n], blue[n])); \
} \
} \
}
WRITE_COLOR_SPAN_FRONTBUFFER(8)
WRITE_COLOR_SPAN_FRONTBUFFER(16)
WRITE_COLOR_SPAN_FRONTBUFFER(24)
WRITE_COLOR_SPAN_FRONTBUFFER(32)
#undef WRITE_COLOR_SPAN_FRONTBUFFER
#define WRITE_COLOR_SPAN(__bpp, __type, __pixel_size) \
static void write_color_span_##__bpp(GLcontext* ctx, \
GLuint n, GLint x, GLint y, \
const GLubyte red[], const GLubyte green[], \
const GLubyte blue[], const GLubyte alpha[], \
const GLubyte mask[] ) \
{ \
struct sw_context* sw_ctx = ctx->DriverCtx; \
struct sw_framebuffer* fb = sw_ctx->fb; \
BYTE* Buffer; \
\
if (sw_ctx->Mode == GL_FRONT) \
{ \
write_color_span_frontbuffer_##__bpp(fb, n, x, y, red, green, blue, mask); \
return; \
} \
\
Buffer = fb->BackBuffer + y * WIDTH_BYTES_ALIGN32(fb->width, __bpp) \
+ (x + n) * __pixel_size; \
if (mask) \
{ \
while (n--) \
{ \
Buffer -= __pixel_size; \
if (mask[n]) \
{ \
PUT_PIXEL_##__bpp((__type*)Buffer, \
PACK_COLOR_##__bpp(red[n], green[n], blue[n])); \
} \
} \
} \
else \
{ \
while (n--) \
{ \
Buffer -= __pixel_size; \
PUT_PIXEL_##__bpp((__type*)Buffer, \
PACK_COLOR_##__bpp(red[n], green[n], blue[n])); \
} \
} \
}
WRITE_COLOR_SPAN(8, BYTE, 1)
WRITE_COLOR_SPAN(16, USHORT, 2)
WRITE_COLOR_SPAN(24, ULONG, 3)
WRITE_COLOR_SPAN(32, ULONG, 4)
#undef WRITE_COLOR_SPAN
static void write_monocolor_span_frontbuffer(struct sw_framebuffer* fb, GLuint n, GLint x, GLint y,
const GLubyte mask[], COLORREF Color)
{
TRACE("Writing monocolor span at %u %u (%u), Color 0x%08x", x, y, n, Color);
if (mask)
{
while (n--)
{
if (mask[n])
SetPixel(fb->Hdc, x + n, y, Color);
}
}
else
{
HBRUSH Brush = CreateSolidBrush(Color);
Brush = SelectObject(fb->Hdc, Brush);
PatBlt(fb->Hdc, x, fb->height - y, n, 1, PATCOPY);
Brush = SelectObject(fb->Hdc, Brush);
DeleteObject(Brush);
}
}
#define WRITE_MONOCOLOR_SPAN(__bpp, __type, __pixel_size) \
static void write_monocolor_span_##__bpp(GLcontext* ctx, \
GLuint n, GLint x, GLint y, \
const GLubyte mask[]) \
{ \
struct sw_context* sw_ctx = ctx->DriverCtx; \
struct sw_framebuffer* fb = sw_ctx->fb; \
BYTE* Buffer; \
\
if (sw_ctx->Mode == GL_FRONT) \
{ \
write_monocolor_span_frontbuffer(fb, n, x, y, mask, \
MAKE_COLORREF_##__bpp(fb->pixel_format, sw_ctx->u##__bpp.CurrentColor)); \
return; \
} \
\
Buffer = fb->BackBuffer + y * WIDTH_BYTES_ALIGN32(fb->width, __bpp) + (x + n) * __pixel_size; \
if (mask) \
{ \
while (n--) \
{ \
Buffer -= __pixel_size; \
if (mask[n]) \
PUT_PIXEL_##__bpp((__type*)Buffer, sw_ctx->u##__bpp.CurrentColor); \
} \
} \
else \
{ \
while(n--) \
{ \
Buffer -= __pixel_size; \
PUT_PIXEL_##__bpp((__type*)Buffer, sw_ctx->u##__bpp.CurrentColor); \
} \
} \
}
WRITE_MONOCOLOR_SPAN(8, BYTE, 1)
WRITE_MONOCOLOR_SPAN(16, USHORT, 2)
WRITE_MONOCOLOR_SPAN(24, ULONG, 3)
WRITE_MONOCOLOR_SPAN(32, ULONG, 4)
#undef WRITE_MONOCOLOR_SPAN
/* Write an array of pixels with a boolean mask. */
#define WRITE_COLOR_PIXELS(__bpp, __type, __pixel_size) \
static void write_color_pixels_##__bpp(GLcontext* ctx, \
GLuint n, const GLint x[], const GLint y[], \
const GLubyte r[], const GLubyte g[], \
const GLubyte b[], const GLubyte a[], \
const GLubyte mask[]) \
{ \
struct sw_context* sw_ctx = ctx->DriverCtx; \
struct sw_framebuffer* fb = sw_ctx->fb; \
\
TRACE("Writing color pixels\n"); \
\
if (sw_ctx->Mode == GL_FRONT) \
{ \
while (n--) \
{ \
if (mask[n]) \
{ \
TRACE("Setting pixel %u, %u to 0x%08x.\n", x[n], fb->height - y[n], \
PACK_COLORREF_##__bpp(r[n], g[n], b[n])); \
SetPixel(fb->Hdc, x[n], fb->height - y[n], \
PACK_COLORREF_##__bpp(r[n], g[n], b[n])); \
} \
} \
\
return; \
} \
\
while (n--) \
{ \
if (mask[n]) \
{ \
BYTE* Buffer = fb->BackBuffer + y[n] * WIDTH_BYTES_ALIGN32(fb->width, __bpp) \
+ x[n] * __pixel_size; \
PUT_PIXEL_##__bpp((__type*)Buffer, PACK_COLOR_##__bpp(r[n], g[n], b[n])); \
} \
} \
}
WRITE_COLOR_PIXELS(8, BYTE, 1)
WRITE_COLOR_PIXELS(16, USHORT, 2)
WRITE_COLOR_PIXELS(24, ULONG, 3)
WRITE_COLOR_PIXELS(32, ULONG, 4)
#undef WRITE_COLOR_PIXELS
static void write_monocolor_pixels_frontbuffer(
struct sw_framebuffer* fb, GLuint n,
const GLint x[], const GLint y[],
const GLubyte mask[], COLORREF Color)
{
TRACE("Writing monocolor pixels to front buffer.\n");
while (n--)
{
if (mask[n])
{
SetPixel(fb->Hdc, x[n], fb->height - y[n], Color);
}
}
}
/*
* Write an array of pixels with a boolean mask. The current color
* is used for all pixels.
*/
#define WRITE_MONOCOLOR_PIXELS(__bpp, __type, __pixel_size) \
static void write_monocolor_pixels_##__bpp(GLcontext* ctx, GLuint n, \
const GLint x[], const GLint y[], \
const GLubyte mask[] ) \
{ \
struct sw_context* sw_ctx = ctx->DriverCtx; \
struct sw_framebuffer* fb = sw_ctx->fb; \
\
if (sw_ctx->Mode == GL_FRONT) \
{ \
write_monocolor_pixels_frontbuffer(fb, n, x, y, mask, \
MAKE_COLORREF_##__bpp(fb->pixel_format, sw_ctx->u##__bpp.CurrentColor)); \
\
return; \
} \
\
while (n--) \
{ \
if (mask[n]) \
{ \
BYTE* Buffer = fb->BackBuffer + y[n] * WIDTH_BYTES_ALIGN32(fb->width, 32) \
+ x[n] * __pixel_size; \
PUT_PIXEL_##__bpp((__type*)Buffer, sw_ctx->u##__bpp.CurrentColor); \
} \
} \
}
WRITE_MONOCOLOR_PIXELS(8, BYTE, 1)
WRITE_MONOCOLOR_PIXELS(16, USHORT, 2)
WRITE_MONOCOLOR_PIXELS(24, ULONG, 3)
WRITE_MONOCOLOR_PIXELS(32, ULONG, 4)
#undef WRITE_MONOCOLOR_PIXELS
/* Write a horizontal span of color pixels with a boolean mask. */
static void write_index_span( GLcontext* ctx,
GLuint n, GLint x, GLint y,
const GLuint index[],
const GLubyte mask[] )
{
ERR("Not implemented yet !\n");
}
/* Write an array of pixels with a boolean mask. */
static void write_index_pixels( GLcontext* ctx,
GLuint n, const GLint x[], const GLint y[],
const GLuint index[], const GLubyte mask[] )
{
ERR("Not implemented yet !\n");
}
/* Read a horizontal span of color-index pixels. */
static void read_index_span( GLcontext* ctx, GLuint n, GLint x, GLint y, GLuint index[])
{
ERR("Not implemented yet !\n");
}
/* Read a horizontal span of color pixels. */
#define READ_COLOR_SPAN(__bpp, __type, __pixel_size) \
static void read_color_span_##__bpp(GLcontext* ctx, \
GLuint n, GLint x, GLint y, \
GLubyte red[], GLubyte green[], \
GLubyte blue[], GLubyte alpha[] ) \
{ \
struct sw_context* sw_ctx = ctx->DriverCtx; \
struct sw_framebuffer* fb = sw_ctx->fb; \
BYTE* Buffer; \
\
if (sw_ctx->Mode == GL_FRONT) \
{ \
COLORREF Color; \
while (n--) \
{ \
Color = GetPixel(fb->Hdc, x + n, fb->height - y); \
UNPACK_COLORREF_##__bpp(Color, &red[n], &green[n], &blue[n]); \
alpha[n] = 0; \
} \
\
return; \
} \
\
Buffer = fb->BackBuffer + y * WIDTH_BYTES_ALIGN32(fb->width, __bpp) \
+ (x + n) * __pixel_size; \
while (n--) \
{ \
Buffer -= __pixel_size; \
UNPACK_COLOR_##__bpp(GET_PIXEL_##__bpp((__type*)Buffer), \
&blue[n], &green[n], &red[n]); \
alpha[n] = 0; \
} \
}
READ_COLOR_SPAN(8, BYTE, 1)
READ_COLOR_SPAN(16, USHORT, 2)
READ_COLOR_SPAN(24, ULONG, 3)
READ_COLOR_SPAN(32, ULONG, 4)
#undef READ_COLOR_SPAN
/* Read an array of color index pixels. */
static void read_index_pixels(GLcontext* ctx,
GLuint n, const GLint x[], const GLint y[],
GLuint index[], const GLubyte mask[])
{
ERR("Not implemented yet !\n");
}
/* Read an array of color pixels. */
#define READ_COLOR_PIXELS(__bpp, __type, __pixel_size) \
static void read_color_pixels_##__bpp(GLcontext* ctx, \
GLuint n, const GLint x[], const GLint y[], \
GLubyte red[], GLubyte green[], \
GLubyte blue[], GLubyte alpha[], \
const GLubyte mask[] ) \
{ \
struct sw_context* sw_ctx = ctx->DriverCtx; \
struct sw_framebuffer* fb = sw_ctx->fb; \
\
if (sw_ctx->Mode == GL_FRONT) \
{ \
COLORREF Color; \
while (n--) \
{ \
if (mask[n]) \
{ \
Color = GetPixel(fb->Hdc, x[n], fb->height - y[n]); \
UNPACK_COLORREF_##__bpp(Color, &red[n], &green[n], &blue[n]); \
alpha[n] = 0; \
} \
} \
\
return; \
} \
\
while (n--) \
{ \
if (mask[n]) \
{ \
BYTE *Buffer = fb->BackBuffer + y[n] * WIDTH_BYTES_ALIGN32(fb->width, __bpp) \
+ x[n] * __pixel_size; \
UNPACK_COLOR_##__bpp(GET_PIXEL_##__bpp((__type*)Buffer), \
&blue[n], &green[n], &red[n]); \
alpha[n] = 0; \
} \
} \
}
READ_COLOR_PIXELS(8, BYTE, 1)
READ_COLOR_PIXELS(16, USHORT, 2)
READ_COLOR_PIXELS(24, ULONG, 3)
READ_COLOR_PIXELS(32, ULONG, 4)
#undef READ_COLOR_PIXELS
static void setup_DD_pointers( GLcontext* ctx )
{
struct sw_context* sw_ctx = ctx->DriverCtx;
ctx->Driver.RendererString = renderer_string;
ctx->Driver.UpdateState = setup_DD_pointers;
switch (sw_ctx->fb->pixel_format->cColorBits)
{
#define HANDLE_BPP(__bpp) \
case __bpp: \
ctx->Driver.ClearIndex = clear_index_##__bpp; \
ctx->Driver.ClearColor = clear_color_##__bpp; \
ctx->Driver.Clear = clear_##__bpp; \
ctx->Driver.Index = set_index_##__bpp; \
ctx->Driver.Color = set_color_##__bpp; \
ctx->Driver.WriteColorSpan = write_color_span_##__bpp; \
ctx->Driver.WriteMonocolorSpan = write_monocolor_span_##__bpp; \
ctx->Driver.WriteMonoindexSpan = write_monocolor_span_##__bpp; \
ctx->Driver.WriteColorPixels = write_color_pixels_##__bpp; \
ctx->Driver.WriteMonocolorPixels = write_monocolor_pixels_##__bpp; \
ctx->Driver.WriteMonoindexPixels = write_monocolor_pixels_##__bpp; \
ctx->Driver.ReadColorSpan = read_color_span_##__bpp; \
ctx->Driver.ReadColorPixels = read_color_pixels_##__bpp; \
break
HANDLE_BPP(8);
HANDLE_BPP(16);
HANDLE_BPP(24);
HANDLE_BPP(32);
#undef HANDLE_BPP
default:
ERR("Unhandled bit depth %u, defaulting to 32bpp.\n", sw_ctx->fb->pixel_format->cColorBits);
ctx->Driver.ClearIndex = clear_index_32;
ctx->Driver.ClearColor = clear_color_32;
ctx->Driver.Clear = clear_32;
ctx->Driver.Index = set_index_32;
ctx->Driver.Color = set_color_32;
ctx->Driver.WriteColorSpan = write_color_span_32;
ctx->Driver.WriteMonocolorSpan = write_monocolor_span_32;
ctx->Driver.WriteMonoindexSpan = write_monocolor_span_32;
ctx->Driver.WriteColorPixels = write_color_pixels_32;
ctx->Driver.WriteMonocolorPixels = write_monocolor_pixels_32;
ctx->Driver.WriteMonoindexPixels = write_monocolor_pixels_32;
ctx->Driver.ReadColorSpan = read_color_span_32;
ctx->Driver.ReadColorPixels = read_color_pixels_32;
break;
}
ctx->Driver.SetBuffer = set_buffer;
ctx->Driver.GetBufferSize = buffer_size;
/* Pixel/span writing functions: */
ctx->Driver.WriteIndexSpan = write_index_span;
ctx->Driver.WriteIndexPixels = write_index_pixels;
/* Pixel/span reading functions: */
ctx->Driver.ReadIndexSpan = read_index_span;
ctx->Driver.ReadIndexPixels = read_index_pixels;
}
/* Declare API table */
#define USE_GL_FUNC(name, proto_args, call_args, offset, stack) extern void WINAPI _mesa_##name proto_args ;
#define USE_GL_FUNC_RET(name, ret_type, proto_args, call_args, offset, stack) extern ret_type WINAPI _mesa_##name proto_args ;
#include "glfuncs.h"
static GLCLTPROCTABLE sw_api_table =
{
OPENGL_VERSION_110_ENTRIES,
{
#define USE_GL_FUNC(name, proto_args, call_args, offset, stack) _mesa_##name,
#include "glfuncs.h"
}
};
/* Glue code */
GLcontext* gl_get_thread_context(void)
{
struct sw_context* sw_ctx = (struct sw_context*)IntGetCurrentDHGLRC();
return sw_ctx->gl_ctx;
}
BOOL sw_SetContext(struct wgl_dc_data* dc_data, DHGLRC dhglrc)
{
struct sw_context* sw_ctx = (struct sw_context*)dhglrc;
struct sw_framebuffer* fb = dc_data->sw_data;
UINT width, height;
/* Get framebuffer size */
if(dc_data->flags & WGL_DC_OBJ_DC)
{
HWND hwnd = dc_data->owner.hwnd;
RECT client_rect;
if(!hwnd)
{
ERR("Physical DC without a window!\n");
return FALSE;
}
if(!GetClientRect(hwnd, &client_rect))
{
ERR("GetClientRect failed!\n");
return FALSE;
}
/* This is a physical DC. Setup the hook */
sw_ctx->hook = SetWindowsHookEx(WH_CALLWNDPROC,
sw_call_window_proc,
NULL,
GetCurrentThreadId());
/* Calculate width & height */
width = client_rect.right - client_rect.left;
height = client_rect.bottom - client_rect.top;
}
else /* OBJ_MEMDC */
{
BITMAP bm;
HBITMAP hbmp;
HDC hdc = dc_data->owner.hdc;
if(fb->gl_visual->DBflag)
{
ERR("Memory DC called with a double buffered format.\n");
return FALSE;
}
hbmp = GetCurrentObject( hdc, OBJ_BITMAP );
if(!hbmp)
{
ERR("No Bitmap!\n");
return FALSE;
}
if(GetObject(hbmp, sizeof(bm), &bm) == 0)
{
ERR("GetObject failed!\n");
return FALSE;
}
width = bm.bmWidth;
height = bm.bmHeight;
}
if(!width) width = 1;
if(!height) height = 1;
/* Also make the mesa context current to mesa */
gl_make_current(sw_ctx->gl_ctx, fb->gl_buffer);
/* Setup our functions */
setup_DD_pointers(sw_ctx->gl_ctx);
/* Set the viewport if this is the first time we initialize this context */
if(sw_ctx->gl_ctx->Viewport.X == 0 &&
sw_ctx->gl_ctx->Viewport.Y == 0 &&
sw_ctx->gl_ctx->Viewport.Width == 0 &&
sw_ctx->gl_ctx->Viewport.Height == 0)
{
gl_Viewport(sw_ctx->gl_ctx, 0, 0, width, height);
}
/* update the framebuffer size */
gl_ResizeBuffersMESA(sw_ctx->gl_ctx);
/* Use our API table */
IntSetCurrentDispatchTable(&sw_api_table.glDispatchTable);
/* We're good */
return TRUE;
}
void sw_ReleaseContext(DHGLRC dhglrc)
{
struct sw_context* sw_ctx = (struct sw_context*)dhglrc;
/* Forward to mesa */
gl_make_current(NULL, NULL);
/* Unhook */
if(sw_ctx->hook)
{
UnhookWindowsHookEx(sw_ctx->hook);
sw_ctx->hook = NULL;
}
}
BOOL sw_SwapBuffers(HDC hdc, struct wgl_dc_data* dc_data)
{
struct sw_framebuffer* fb = dc_data->sw_data;
char Buffer[sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD)];
BITMAPINFO *bmi = (BITMAPINFO*)Buffer;
BYTE Bpp = fb->pixel_format->cColorBits;
if (!fb->gl_visual->DBflag)
return TRUE;
if (!fb->BackBuffer)
return FALSE;
bmi->bmiHeader.biSize = sizeof(bmi->bmiHeader);
bmi->bmiHeader.biBitCount = Bpp;
bmi->bmiHeader.biClrImportant = 0;
bmi->bmiHeader.biClrUsed = 0;
bmi->bmiHeader.biPlanes = 1;
bmi->bmiHeader.biSizeImage = WIDTH_BYTES_ALIGN32(fb->width, Bpp) * fb->height;
bmi->bmiHeader.biXPelsPerMeter = 0;
bmi->bmiHeader.biYPelsPerMeter = 0;
bmi->bmiHeader.biHeight = fb->height;
bmi->bmiHeader.biWidth = fb->width;
bmi->bmiHeader.biCompression = Bpp == 16 ? BI_BITFIELDS : BI_RGB;
if (Bpp == 16)
{
DWORD* BitMasks = (DWORD*)(&bmi->bmiColors[0]);
BitMasks[0] = 0x0000F800;
BitMasks[1] = 0x000007E0;
BitMasks[2] = 0x0000001F;
}
return SetDIBitsToDevice(fb->Hdc, 0, 0, fb->width, fb->height, 0, 0, 0, fb->height, fb->BackBuffer, bmi,
fb->pixel_format->iPixelType == PFD_TYPE_COLORINDEX ? DIB_PAL_COLORS : DIB_RGB_COLORS) != 0;
}