mesa/src/hgl/GLView.cpp
Alexander von Gluck IV 61ef697afc haiku libGL: Move from gallium target to src/hgl
* The Haiku renderers need to link to libGL to function properly
  in all usage contexts. As mesa drivers build before gallium
  targets, we couldn't properly link the mesa swrast driver to
  the gallium libGL target for Haiku.
* This is likely better as it mimics how glx is laid out ensuring
  the Haiku libGL is better understood.
* All renderers properly link in libGL now.

Acked-by: Brian Paul <brianp@vmware.com>
2014-01-06 15:50:21 -06:00

643 lines
11 KiB
C++

/*
* Copyright 2006-2012, Haiku. 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
* Stefano Ceccherini, burton666@libero.it
*/
#include <kernel/image.h>
#include <GLView.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <DirectWindow.h>
#include <GLRenderer.h>
#include "interface/DirectWindowPrivate.h"
#include "GLDispatcher.h"
#include "GLRendererRoster.h"
struct glview_direct_info {
direct_buffer_info* direct_info;
bool direct_connected;
bool enable_direct_mode;
glview_direct_info();
~glview_direct_info();
};
BGLView::BGLView(BRect rect, const char* name, ulong resizingMode, ulong mode,
ulong options)
:
BView(rect, name, B_FOLLOW_ALL_SIDES, mode | B_WILL_DRAW | B_FRAME_EVENTS),
// | B_FULL_UPDATE_ON_RESIZE)
fGc(NULL),
fOptions(options),
fDitherCount(0),
fDrawLock("BGLView draw lock"),
fDisplayLock("BGLView display lock"),
fClipInfo(NULL),
fRenderer(NULL),
fRoster(NULL),
fDitherMap(NULL)
{
fRoster = new GLRendererRoster(this, options);
}
BGLView::~BGLView()
{
delete fClipInfo;
if (fRenderer)
fRenderer->Release();
}
void
BGLView::LockGL()
{
// TODO: acquire the OpenGL API lock it on this glview
fDisplayLock.Lock();
if (fRenderer)
fRenderer->LockGL();
}
void
BGLView::UnlockGL()
{
if (fRenderer)
fRenderer->UnlockGL();
fDisplayLock.Unlock();
// TODO: release the GL API lock to others glviews
}
void
BGLView::SwapBuffers()
{
SwapBuffers(false);
}
void
BGLView::SwapBuffers(bool vSync)
{
if (fRenderer) {
_LockDraw();
fRenderer->SwapBuffers(vSync);
_UnlockDraw();
}
}
BView*
BGLView::EmbeddedView()
{
return NULL;
}
void*
BGLView::GetGLProcAddress(const char* procName)
{
BGLDispatcher* glDispatcher = NULL;
if (fRenderer)
glDispatcher = fRenderer->GLDispatcher();
if (glDispatcher)
return (void*)glDispatcher->AddressOf(procName);
return NULL;
}
status_t
BGLView::CopyPixelsOut(BPoint source, BBitmap* dest)
{
if (!fRenderer)
return B_ERROR;
if (!dest || !dest->Bounds().IsValid())
return B_BAD_VALUE;
return fRenderer->CopyPixelsOut(source, dest);
}
status_t
BGLView::CopyPixelsIn(BBitmap* source, BPoint dest)
{
if (!fRenderer)
return B_ERROR;
if (!source || !source->Bounds().IsValid())
return B_BAD_VALUE;
return fRenderer->CopyPixelsIn(source, dest);
}
/*! Mesa's GLenum is not ulong but uint, so we can't use GLenum
without breaking this method signature.
Instead, we have to use the effective BeOS's SGI OpenGL GLenum type:
unsigned long.
*/
void
BGLView::ErrorCallback(unsigned long errorCode)
{
char msg[32];
sprintf(msg, "GL: Error code $%04lx.", errorCode);
// TODO: under BeOS R5, it call debugger(msg);
fprintf(stderr, "%s\n", msg);
}
void
BGLView::Draw(BRect updateRect)
{
if (fRenderer) {
_LockDraw();
fRenderer->Draw(updateRect);
_UnlockDraw();
return;
}
// TODO: auto-size and center the string
MovePenTo(8, 32);
DrawString("No OpenGL renderer available!");
}
void
BGLView::AttachedToWindow()
{
BView::AttachedToWindow();
fBounds = Bounds();
for (BView* view = this; view != NULL; view = view->Parent())
view->ConvertToParent(&fBounds);
fRenderer = fRoster->GetRenderer();
if (fRenderer != NULL) {
// Jackburton: The following code was commented because it doesn't look
// good in "direct" mode:
// when the window is moved, the app_server doesn't paint the view's
// background, and the stuff behind the window itself shows up.
// Setting the view color to black, instead, looks a bit more elegant.
#if 0
// Don't paint white window background when resized
SetViewColor(B_TRANSPARENT_32_BIT);
#else
SetViewColor(0, 0, 0);
#endif
// Set default OpenGL viewport:
LockGL();
glViewport(0, 0, Bounds().IntegerWidth(), Bounds().IntegerHeight());
UnlockGL();
fRenderer->FrameResized(Bounds().IntegerWidth(),
Bounds().IntegerHeight());
if (fClipInfo) {
fRenderer->DirectConnected(fClipInfo->direct_info);
fRenderer->EnableDirectMode(fClipInfo->enable_direct_mode);
}
return;
}
fprintf(stderr, "no renderer found! \n");
// No Renderer, no rendering. Setup a minimal "No Renderer" string drawing
// context
SetFont(be_bold_font);
// SetFontSize(16);
}
void
BGLView::AllAttached()
{
BView::AllAttached();
}
void
BGLView::DetachedFromWindow()
{
if (fRenderer)
fRenderer->Release();
fRenderer = NULL;
BView::DetachedFromWindow();
}
void
BGLView::AllDetached()
{
BView::AllDetached();
}
void
BGLView::FrameResized(float width, float height)
{
fBounds = Bounds();
for (BView* v = this; v; v = v->Parent())
v->ConvertToParent(&fBounds);
if (fRenderer) {
LockGL();
_LockDraw();
_CallDirectConnected();
fRenderer->FrameResized(width, height);
_UnlockDraw();
UnlockGL();
}
BView::FrameResized(width, height);
}
status_t
BGLView::Perform(perform_code d, void* arg)
{
return BView::Perform(d, arg);
}
status_t
BGLView::Archive(BMessage* data, bool deep) const
{
return BView::Archive(data, deep);
}
void
BGLView::MessageReceived(BMessage* msg)
{
BView::MessageReceived(msg);
}
void
BGLView::SetResizingMode(uint32 mode)
{
BView::SetResizingMode(mode);
}
void
BGLView::GetPreferredSize(float* _width, float* _height)
{
if (_width)
*_width = 0;
if (_height)
*_height = 0;
}
void
BGLView::Show()
{
BView::Show();
}
void
BGLView::Hide()
{
BView::Hide();
}
BHandler*
BGLView::ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier,
int32 form, const char* property)
{
return BView::ResolveSpecifier(msg, index, specifier, form, property);
}
status_t
BGLView::GetSupportedSuites(BMessage* data)
{
return BView::GetSupportedSuites(data);
}
void
BGLView::DirectConnected(direct_buffer_info* info)
{
if (fClipInfo == NULL) {
fClipInfo = new (std::nothrow) glview_direct_info();
if (fClipInfo == NULL)
return;
}
direct_buffer_info* localInfo = fClipInfo->direct_info;
switch (info->buffer_state & B_DIRECT_MODE_MASK) {
case B_DIRECT_START:
fClipInfo->direct_connected = true;
memcpy(localInfo, info, DIRECT_BUFFER_INFO_AREA_SIZE);
_UnlockDraw();
break;
case B_DIRECT_MODIFY:
_LockDraw();
memcpy(localInfo, info, DIRECT_BUFFER_INFO_AREA_SIZE);
_UnlockDraw();
break;
case B_DIRECT_STOP:
fClipInfo->direct_connected = false;
_LockDraw();
break;
}
if (fRenderer)
_CallDirectConnected();
}
void
BGLView::EnableDirectMode(bool enabled)
{
if (fRenderer)
fRenderer->EnableDirectMode(enabled);
if (fClipInfo == NULL) {
fClipInfo = new (std::nothrow) glview_direct_info();
if (fClipInfo == NULL)
return;
}
fClipInfo->enable_direct_mode = enabled;
}
void
BGLView::_LockDraw()
{
if (!fClipInfo || !fClipInfo->enable_direct_mode)
return;
fDrawLock.Lock();
}
void
BGLView::_UnlockDraw()
{
if (!fClipInfo || !fClipInfo->enable_direct_mode)
return;
fDrawLock.Unlock();
}
void
BGLView::_CallDirectConnected()
{
if (!fClipInfo)
return;
direct_buffer_info* localInfo = fClipInfo->direct_info;
direct_buffer_info* info = (direct_buffer_info*)malloc(
DIRECT_BUFFER_INFO_AREA_SIZE);
if (info == NULL)
return;
memcpy(info, localInfo, DIRECT_BUFFER_INFO_AREA_SIZE);
// Collect the rects into a BRegion, then clip to the view's bounds
BRegion region;
for (uint32 c = 0; c < localInfo->clip_list_count; c++)
region.Include(localInfo->clip_list[c]);
BRegion boundsRegion = fBounds.OffsetByCopy(localInfo->window_bounds.left,
localInfo->window_bounds.top);
info->window_bounds = boundsRegion.RectAtInt(0);
// window_bounds are now view bounds
region.IntersectWith(&boundsRegion);
info->clip_list_count = region.CountRects();
info->clip_bounds = region.FrameInt();
for (uint32 c = 0; c < info->clip_list_count; c++)
info->clip_list[c] = region.RectAtInt(c);
fRenderer->DirectConnected(info);
free(info);
}
//---- virtual reserved methods ----------
void BGLView::_ReservedGLView1() {}
void BGLView::_ReservedGLView2() {}
void BGLView::_ReservedGLView3() {}
void BGLView::_ReservedGLView4() {}
void BGLView::_ReservedGLView5() {}
void BGLView::_ReservedGLView6() {}
void BGLView::_ReservedGLView7() {}
void BGLView::_ReservedGLView8() {}
// #pragma mark -
// BeOS compatibility: contrary to others BView's contructors,
// BGLView one wants a non-const name argument.
BGLView::BGLView(BRect rect, char* name, ulong resizingMode, ulong mode,
ulong options)
:
BView(rect, name, B_FOLLOW_ALL_SIDES, mode | B_WILL_DRAW | B_FRAME_EVENTS),
fGc(NULL),
fOptions(options),
fDitherCount(0),
fDrawLock("BGLView draw lock"),
fDisplayLock("BGLView display lock"),
fClipInfo(NULL),
fRenderer(NULL),
fRoster(NULL),
fDitherMap(NULL)
{
fRoster = new GLRendererRoster(this, options);
}
#if 0
// TODO: implement BGLScreen class...
BGLScreen::BGLScreen(char* name, ulong screenMode, ulong options,
status_t* error, bool debug)
:
BWindowScreen(name, screenMode, error, debug)
{
}
BGLScreen::~BGLScreen()
{
}
void
BGLScreen::LockGL()
{
}
void
BGLScreen::UnlockGL()
{
}
void
BGLScreen::SwapBuffers()
{
}
void
BGLScreen::ErrorCallback(unsigned long errorCode)
{
// Mesa's GLenum is not ulong but uint!
char msg[32];
sprintf(msg, "GL: Error code $%04lx.", errorCode);
// debugger(msg);
fprintf(stderr, "%s\n", msg);
return;
}
void
BGLScreen::ScreenConnected(bool enabled)
{
}
void
BGLScreen::FrameResized(float width, float height)
{
return BWindowScreen::FrameResized(width, height);
}
status_t
BGLScreen::Perform(perform_code d, void* arg)
{
return BWindowScreen::Perform(d, arg);
}
status_t
BGLScreen::Archive(BMessage* data, bool deep) const
{
return BWindowScreen::Archive(data, deep);
}
void
BGLScreen::MessageReceived(BMessage* msg)
{
BWindowScreen::MessageReceived(msg);
}
void
BGLScreen::Show()
{
BWindowScreen::Show();
}
void
BGLScreen::Hide()
{
BWindowScreen::Hide();
}
BHandler*
BGLScreen::ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier,
int32 form, const char* property)
{
return BWindowScreen::ResolveSpecifier(msg, index, specifier,
form, property);
}
status_t
BGLScreen::GetSupportedSuites(BMessage* data)
{
return BWindowScreen::GetSupportedSuites(data);
}
//---- virtual reserved methods ----------
void BGLScreen::_ReservedGLScreen1() {}
void BGLScreen::_ReservedGLScreen2() {}
void BGLScreen::_ReservedGLScreen3() {}
void BGLScreen::_ReservedGLScreen4() {}
void BGLScreen::_ReservedGLScreen5() {}
void BGLScreen::_ReservedGLScreen6() {}
void BGLScreen::_ReservedGLScreen7() {}
void BGLScreen::_ReservedGLScreen8() {}
#endif
const char* color_space_name(color_space space)
{
#define C2N(a) case a: return #a
switch (space) {
C2N(B_RGB24);
C2N(B_RGB32);
C2N(B_RGBA32);
C2N(B_RGB32_BIG);
C2N(B_RGBA32_BIG);
C2N(B_GRAY8);
C2N(B_GRAY1);
C2N(B_RGB16);
C2N(B_RGB15);
C2N(B_RGBA15);
C2N(B_CMAP8);
default:
return "Unknown!";
};
#undef C2N
};
glview_direct_info::glview_direct_info()
{
// TODO: See direct_window_data() in app_server's ServerWindow.cpp
direct_info = (direct_buffer_info*)calloc(1, DIRECT_BUFFER_INFO_AREA_SIZE);
direct_connected = false;
enable_direct_mode = false;
}
glview_direct_info::~glview_direct_info()
{
free(direct_info);
}