317 lines
6.4 KiB
C++
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;
|
|
}
|