/*
|
* 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, BGLDispatcher *dispatcher)
|
{
|
return new SoftwareRenderer(view, opts, dispatcher);
|
}
|
|
SoftwareRenderer::SoftwareRenderer(BGLView *view, ulong options,
|
BGLDispatcher* dispatcher)
|
:
|
BGLRenderer(view, options, dispatcher),
|
fBitmap(NULL),
|
fDirectModeEnabled(false),
|
fInfo(NULL),
|
fInfoLocker("info locker"),
|
fOptions(options),
|
fColorSpace(B_NO_COLOR_SPACE)
|
{
|
CALLED();
|
|
// Disable double buffer for the moment.
|
//options &= ~BGL_DOUBLE;
|
|
// 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));
|
|
// Allocate a bitmap
|
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();
|
|
_AllocateBitmap();
|
|
// Initialize the first "Haiku Software GL Pipe" context
|
beg = time(NULL);
|
fContextID = fContextObj->CreateContext(fBitmap);
|
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;
|
if (fBitmap)
|
delete fBitmap;
|
}
|
|
|
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;
|
}
|
|
if (fBitmap && cs == fColorSpace && fContextObj->Validate(fWidth, fHeight)) {
|
fContextObj->SetCurrentContext(fBitmap, fContextID);
|
return;
|
}
|
|
fColorSpace = cs;
|
|
_AllocateBitmap();
|
fContextObj->SetCurrentContext(fBitmap, fContextID);
|
}
|
|
|
void
|
SoftwareRenderer::UnlockGL()
|
{
|
// CALLED();
|
if ((fOptions & BGL_DOUBLE) == 0) {
|
SwapBuffers();
|
}
|
fContextObj->SetCurrentContext(NULL, fContextID);
|
BGLRenderer::UnlockGL();
|
}
|
|
|
void
|
SoftwareRenderer::SwapBuffers(bool vsync)
|
{
|
// CALLED();
|
if (!fBitmap)
|
return;
|
|
BScreen screen(GLView()->Window());
|
|
fContextObj->SwapBuffers(fContextID);
|
|
BAutolock lock(fInfoLocker);
|
|
if (!fDirectModeEnabled || fInfo == NULL) {
|
if (GLView()->LockLooperWithTimeout(1000) == B_OK) {
|
GLView()->DrawBitmap(fBitmap, B_ORIGIN);
|
GLView()->UnlockLooper();
|
if (vsync)
|
screen.WaitForRetrace();
|
}
|
return;
|
}
|
|
// check the bitmap size still matches the size
|
if (fInfo->window_bounds.bottom - fInfo->window_bounds.top
|
!= fBitmap->Bounds().IntegerHeight()
|
|| fInfo->window_bounds.right - fInfo->window_bounds.left
|
!= fBitmap->Bounds().IntegerWidth()) {
|
ERROR("%s: Bitmap size doesn't match size!\n", __func__);
|
return;
|
}
|
|
uint32 bytesPerRow = fBitmap->BytesPerRow();
|
uint8 bytesPerPixel = bytesPerRow / fBitmap->Bounds().IntegerWidth();
|
|
for (uint32 i = 0; i < fInfo->clip_list_count; i++) {
|
clipping_rect *clip = &fInfo->clip_list[i];
|
int32 height = clip->bottom - clip->top + 1;
|
int32 bytesWidth
|
= (clip->right - clip->left + 1) * bytesPerPixel;
|
bytesWidth -= bytesPerPixel;
|
uint8 *p = (uint8 *)fInfo->bits + clip->top
|
* fInfo->bytes_per_row + clip->left * bytesPerPixel;
|
uint8 *b = (uint8 *)fBitmap->Bits()
|
+ (clip->top - fInfo->window_bounds.top) * bytesPerRow
|
+ (clip->left - fInfo->window_bounds.left) * bytesPerPixel;
|
|
for (int y = 0; y < height - 1; y++) {
|
memcpy(p, b, bytesWidth);
|
p += fInfo->bytes_per_row;
|
b += bytesPerRow;
|
}
|
}
|
|
if (vsync)
|
screen.WaitForRetrace();
|
}
|
|
|
void
|
SoftwareRenderer::Draw(BRect updateRect)
|
{
|
// CALLED();
|
if ((!fDirectModeEnabled || fInfo == NULL) && fBitmap)
|
GLView()->DrawBitmap(fBitmap, updateRect, updateRect);
|
}
|
|
|
status_t
|
SoftwareRenderer::CopyPixelsOut(BPoint location, BBitmap *bitmap)
|
{
|
CALLED();
|
color_space scs = fBitmap->ColorSpace();
|
color_space dcs = bitmap->ColorSpace();
|
|
if (scs != dcs && (scs != B_RGBA32 || dcs != B_RGB32)) {
|
ERROR("%s::CopyPixelsOut(): incompatible color space: %s != %s\n",
|
__PRETTY_FUNCTION__, color_space_name(scs), color_space_name(dcs));
|
return B_BAD_TYPE;
|
}
|
|
BRect sr = fBitmap->Bounds();
|
BRect dr = bitmap->Bounds();
|
|
// int32 w1 = sr.IntegerWidth();
|
// int32 h1 = sr.IntegerHeight();
|
// int32 w2 = dr.IntegerWidth();
|
// int32 h2 = dr.IntegerHeight();
|
|
sr = sr & dr.OffsetBySelf(location);
|
dr = sr.OffsetByCopy(-location.x, -location.y);
|
|
uint8 *ps = (uint8 *) fBitmap->Bits();
|
uint8 *pd = (uint8 *) bitmap->Bits();
|
uint32 *s, *d;
|
uint32 y;
|
for (y = (uint32) sr.top; y <= (uint32) sr.bottom; y++) {
|
s = (uint32 *)(ps + y * fBitmap->BytesPerRow());
|
s += (uint32) sr.left;
|
|
d = (uint32 *)(pd + (y + (uint32)(dr.top - sr.top))
|
* bitmap->BytesPerRow());
|
d += (uint32) dr.left;
|
memcpy(d, s, dr.IntegerWidth() * 4);
|
}
|
|
return B_OK;
|
}
|
|
|
status_t
|
SoftwareRenderer::CopyPixelsIn(BBitmap *bitmap, BPoint location)
|
{
|
CALLED();
|
|
color_space sourceCS = bitmap->ColorSpace();
|
color_space destinationCS = fBitmap->ColorSpace();
|
|
if (sourceCS != destinationCS
|
&& (sourceCS != B_RGB32 || destinationCS != B_RGBA32)) {
|
ERROR("%s::CopyPixelsIn(): incompatible color space: %s != %s\n",
|
__PRETTY_FUNCTION__, color_space_name(sourceCS),
|
color_space_name(destinationCS));
|
return B_BAD_TYPE;
|
}
|
|
BRect sr = bitmap->Bounds();
|
BRect dr = fBitmap->Bounds();
|
|
sr = sr & dr.OffsetBySelf(location);
|
dr = sr.OffsetByCopy(-location.x, -location.y);
|
|
uint8 *ps = (uint8 *) bitmap->Bits();
|
uint8 *pd = (uint8 *) fBitmap->Bits();
|
uint32 *s, *d;
|
uint32 y;
|
|
for (y = (uint32) sr.top; y <= (uint32) sr.bottom; y++) {
|
s = (uint32 *)(ps + y * bitmap->BytesPerRow());
|
s += (uint32) sr.left;
|
|
d = (uint32 *)(pd + (y + (uint32)(dr.top - sr.top))
|
* fBitmap->BytesPerRow());
|
d += (uint32) dr.left;
|
|
memcpy(d, s, dr.IntegerWidth() * 4);
|
}
|
|
return B_OK;
|
}
|
|
|
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;
|
}
|
|
|
void
|
SoftwareRenderer::_AllocateBitmap()
|
{
|
// CALLED();
|
|
// allocate new size of back buffer bitmap
|
BAutolock lock(fInfoLocker);
|
if (fBitmap)
|
delete fBitmap;
|
|
if (fWidth < 1 || fHeight < 1) {
|
TRACE("%s: Can't allocate bitmap of %dx%d\n", __func__,
|
fWidth, fHeight);
|
return;
|
}
|
BRect rect(0.0, 0.0, fWidth, fHeight);
|
fBitmap = new (std::nothrow) BBitmap(rect, fColorSpace);
|
if (fBitmap == NULL) {
|
TRACE("%s: Can't create bitmap!\n", __func__);
|
return;
|
}
|
|
TRACE("%s: New bitmap size: %" B_PRId32 " x %" B_PRId32 "\n", __func__,
|
fBitmap->Bounds().IntegerWidth(), fBitmap->Bounds().IntegerHeight());
|
|
#if 0
|
// debug..
|
void *data = fBitmap->Bits();
|
memset(data, 0xcc, fBitmap->BitsLength());
|
#endif
|
}
|