mesa/src/gallium/targets/haiku-softpipe/SoftwareRenderer.cpp

317 lines
6.4 KiB
C++

/*
* Copyright 2006-2012, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jérôme Duval, korli@users.berlios.de
* Philippe Houdoin, philippe.houdoin@free.fr
* Artur Wyszynski, harakash@gmail.com
* Alexander von Gluck IV, kallisti5@unixzen.com
*/
#include "SoftwareRenderer.h"
#include <Autolock.h>
#include <interface/DirectWindowPrivate.h>
#include <GraphicsDefs.h>
#include <Screen.h>
#include <stdio.h>
#include <sys/time.h>
#include <new>
#ifdef DEBUG
# define TRACE(x...) printf("SoftwareRenderer: " x)
# define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__)
#else
# define TRACE(x...)
# define CALLED()
#endif
#define ERROR(x...) printf("SoftwareRenderer: " x)
extern const char* color_space_name(color_space space);
extern "C" _EXPORT BGLRenderer*
instantiate_gl_renderer(BGLView *view, ulong opts)
{
return new SoftwareRenderer(view, opts);
}
struct RasBuf32
{
int32 width, height, stride;
int32 orgX, orgY;
int32 *colors;
RasBuf32(int32 width, int32 height, int32 stride, int32 orgX, int32 orgY, int32 *colors):
width(width), height(height), stride(stride), orgX(orgX), orgY(orgY), colors(colors)
{}
RasBuf32(BBitmap *bmp)
{
width = bmp->Bounds().IntegerWidth() + 1;
height = bmp->Bounds().IntegerHeight() + 1;
stride = bmp->BytesPerRow()/4;
orgX = 0;
orgY = 0;
colors = (int32*)bmp->Bits();
}
RasBuf32(direct_buffer_info *info)
{
width = 0x7fffffff;
height = 0x7fffffff;
stride = info->bytes_per_row/4;
orgX = 0;
orgY = 0;
colors = (int32*)info->bits;
}
void ClipSize(int32 x, int32 y, int32 w, int32 h)
{
if (x < 0) {w += x; x = 0;}
if (y < 0) {h += y; y = 0;}
if (x + w > width) {w = width - x;}
if (y + h > height) {h = height - y;}
if ((w > 0) && (h > 0)) {
colors += y*stride + x;
width = w;
height = h;
} else {
width = 0; height = 0; colors = NULL;
}
if (x + orgX > 0) {orgX += x;} else {orgX = 0;}
if (y + orgY > 0) {orgY += y;} else {orgY = 0;}
}
void ClipRect(int32 l, int32 t, int32 r, int32 b)
{
ClipSize(l, t, r - l, b - t);
}
void Shift(int32 dx, int32 dy)
{
orgX += dx;
orgY += dy;
}
void Clear(int32 color)
{
RasBuf32 dst = *this;
dst.stride -= dst.width;
for (; dst.height > 0; dst.height--) {
for (int32 i = dst.width; i > 0; i--)
*dst.colors++ = color;
dst.colors += dst.stride;
}
}
void Blit(RasBuf32 src)
{
RasBuf32 dst = *this;
int32 x, y;
x = src.orgX - orgX;
y = src.orgY - orgY;
dst.ClipSize(x, y, src.width, src.height);
src.ClipSize(-x, -y, width, height);
for (; dst.height > 0; dst.height--) {
memcpy(dst.colors, src.colors, 4*dst.width);
dst.colors += dst.stride;
src.colors += src.stride;
}
}
};
SoftwareRenderer::SoftwareRenderer(BGLView *view, ulong options)
:
BGLRenderer(view, options),
fDirectModeEnabled(false),
fInfo(NULL),
fInfoLocker("info locker"),
fOptions(options),
fColorSpace(B_NO_COLOR_SPACE)
{
CALLED();
// Initialize the "Haiku Software GL Pipe"
time_t beg;
time_t end;
beg = time(NULL);
fContextObj = new GalliumContext(options);
end = time(NULL);
TRACE("Haiku Software GL Pipe initialization time: %f.\n",
difftime(end, beg));
BRect b = view->Bounds();
fColorSpace = BScreen(view->Window()).ColorSpace();
TRACE("%s: Colorspace:\t%s\n", __func__, color_space_name(fColorSpace));
fWidth = (GLint)b.IntegerWidth();
fHeight = (GLint)b.IntegerHeight();
// Initialize the first "Haiku Software GL Pipe" context
beg = time(NULL);
fContextID = fContextObj->CreateContext(this);
end = time(NULL);
if (fContextID < 0)
ERROR("%s: There was an error creating the context!\n", __func__);
else {
TRACE("%s: Haiku Software GL Pipe context creation time: %f.\n",
__func__, difftime(end, beg));
}
if (!fContextObj->GetCurrentContext())
LockGL();
}
SoftwareRenderer::~SoftwareRenderer()
{
CALLED();
if (fContextObj)
delete fContextObj;
}
void
SoftwareRenderer::LockGL()
{
// CALLED();
BGLRenderer::LockGL();
color_space cs = BScreen(GLView()->Window()).ColorSpace();
{
BAutolock lock(fInfoLocker);
if (fDirectModeEnabled && fInfo != NULL) {
fWidth = fInfo->window_bounds.right - fInfo->window_bounds.left;
fHeight = fInfo->window_bounds.bottom - fInfo->window_bounds.top;
}
fContextObj->Validate(fWidth, fHeight);
fColorSpace = cs;
}
// do not hold fInfoLocker here to avoid deadlock
fContextObj->SetCurrentContext(true, fContextID);
}
void
SoftwareRenderer::UnlockGL()
{
// CALLED();
if ((fOptions & BGL_DOUBLE) == 0) {
SwapBuffers();
}
fContextObj->SetCurrentContext(false, fContextID);
BGLRenderer::UnlockGL();
}
void
SoftwareRenderer::Display(BBitmap *bitmap, BRect *updateRect)
{
// CALLED();
if (!fDirectModeEnabled) {
// TODO: avoid timeout
if (GLView()->LockLooperWithTimeout(1000) == B_OK) {
GLView()->DrawBitmap(bitmap, B_ORIGIN);
GLView()->UnlockLooper();
}
} else {
BAutolock lock(fInfoLocker);
if (fInfo != NULL) {
RasBuf32 srcBuf(bitmap);
RasBuf32 dstBuf(fInfo);
for (uint32 i = 0; i < fInfo->clip_list_count; i++) {
clipping_rect *clip = &fInfo->clip_list[i];
RasBuf32 dstClip = dstBuf;
dstClip.ClipRect(clip->left, clip->top, clip->right + 1, clip->bottom + 1);
dstClip.Shift(-fInfo->window_bounds.left, -fInfo->window_bounds.top);
dstClip.Blit(srcBuf);
}
}
}
}
void
SoftwareRenderer::SwapBuffers(bool vsync)
{
BScreen screen(GLView()->Window());
fContextObj->SwapBuffers(fContextID);
fContextObj->Validate(fWidth, fHeight);
if (vsync)
screen.WaitForRetrace();
}
void
SoftwareRenderer::Draw(BRect updateRect)
{
// CALLED();
fContextObj->Draw(fContextID, updateRect);
}
status_t
SoftwareRenderer::CopyPixelsOut(BPoint location, BBitmap *bitmap)
{
CALLED();
// TODO: implement
return B_ERROR;
}
status_t
SoftwareRenderer::CopyPixelsIn(BBitmap *bitmap, BPoint location)
{
CALLED();
// TODO: implement
return B_ERROR;
}
void
SoftwareRenderer::EnableDirectMode(bool enabled)
{
fDirectModeEnabled = enabled;
}
void
SoftwareRenderer::DirectConnected(direct_buffer_info *info)
{
// CALLED();
BAutolock lock(fInfoLocker);
if (info) {
if (!fInfo) {
fInfo = (direct_buffer_info *)calloc(1,
DIRECT_BUFFER_INFO_AREA_SIZE);
}
memcpy(fInfo, info, DIRECT_BUFFER_INFO_AREA_SIZE);
} else if (fInfo) {
free(fInfo);
fInfo = NULL;
}
}
void
SoftwareRenderer::FrameResized(float width, float height)
{
TRACE("%s: %f x %f\n", __func__, width, height);
BAutolock lock(fInfoLocker);
fWidth = (GLuint)width;
fHeight = (GLuint)height;
}