From 153dd4767eee2c6fa7dcb32828e24676906fa976 Mon Sep 17 00:00:00 2001 From: Alexander von Gluck IV Date: Tue, 27 Nov 2012 19:55:16 -0600 Subject: [PATCH] softpipe: Initial work on Gallium renderer * This is still early, but I want to track the development in tree. * swpipe will support Gallium softpipe or llvmpipe (llvm pipe will give improved software rendering permance when llvm is included at os build time) * Used Artur Wyszynski's original code as a road map... however a *lot* has changed. * Crashes at startup.. not in image yet --- src/add-ons/opengl/Jamfile | 3 + src/add-ons/opengl/swpipe/GalliumContext.cpp | 546 ++++++++++++++++++ src/add-ons/opengl/swpipe/GalliumContext.h | 75 +++ src/add-ons/opengl/swpipe/Jamfile | 26 + .../opengl/swpipe/SoftwareRenderer.cpp | 359 ++++++++++++ src/add-ons/opengl/swpipe/SoftwareRenderer.h | 57 ++ src/add-ons/opengl/swpipe/bitmap_wrapper.cpp | 117 ++++ src/add-ons/opengl/swpipe/bitmap_wrapper.h | 42 ++ 8 files changed, 1225 insertions(+) create mode 100644 src/add-ons/opengl/swpipe/GalliumContext.cpp create mode 100644 src/add-ons/opengl/swpipe/GalliumContext.h create mode 100644 src/add-ons/opengl/swpipe/Jamfile create mode 100644 src/add-ons/opengl/swpipe/SoftwareRenderer.cpp create mode 100644 src/add-ons/opengl/swpipe/SoftwareRenderer.h create mode 100644 src/add-ons/opengl/swpipe/bitmap_wrapper.cpp create mode 100644 src/add-ons/opengl/swpipe/bitmap_wrapper.h diff --git a/src/add-ons/opengl/Jamfile b/src/add-ons/opengl/Jamfile index 79498b12f16..7f405b3d2e5 100644 --- a/src/add-ons/opengl/Jamfile +++ b/src/add-ons/opengl/Jamfile @@ -4,6 +4,9 @@ SubDir HAIKU_TOP src add-ons opengl ; SubInclude HAIKU_TOP src add-ons opengl swrast ; SubInclude HAIKU_TOP src add-ons opengl swrast_legacy ; +# Haiku Gallium Software Renderer +SubInclude HAIKU_TOP src add-ons opengl swpipe ; + # SubInclude HAIKU_TOP src add-ons opengl nvidia ; # SubInclude HAIKU_TOP src add-ons opengl radeon ; diff --git a/src/add-ons/opengl/swpipe/GalliumContext.cpp b/src/add-ons/opengl/swpipe/GalliumContext.cpp new file mode 100644 index 00000000000..41ac9f96976 --- /dev/null +++ b/src/add-ons/opengl/swpipe/GalliumContext.cpp @@ -0,0 +1,546 @@ +/* + * Copyright 2012, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Artur Wyszynski, harakash@gmail.com + * Alexander von Gluck IV, kallisti5@unixzen.com + */ + + +#include "GalliumContext.h" + +#include "GLView.h" + +#include "bitmap_wrapper.h" +extern "C" { +#include "glapi/glapi.h" +#include "main/context.h" +#include "main/framebuffer.h" +#include "main/renderbuffer.h" +#include "pipe/p_format.h" +#include "state_tracker/st_cb_fbo.h" +#include "state_tracker/st_cb_flush.h" +#include "state_tracker/st_context.h" +#include "state_tracker/st_gl_api.h" +#include "state_tracker/st_manager.h" +#include "state_tracker/sw_winsys.h" +#include "softpipe/sp_context.h" +#include "softpipe/sp_public.h" +#include "softpipe/sp_texture.h" +#ifdef USE_LLVMPIPE +#include "llvmpipe/lp_context.h" +#include "llvmpipe/lp_public.h" +#include "llvmpipe/lp_texture.h" +#endif +} + + +#define TRACE_CONTEXT +#ifdef TRACE_CONTEXT +# define TRACE(x...) printf("GalliumContext: " x) +# define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__) +#else +# define TRACE(x...) +# define CALLED() +#endif +#define ERROR(x...) printf("GalliumContext: " x) + + +#if 0 +static void +hgl_viewport(struct gl_context* glctx, GLint x, GLint y, + GLsizei width, GLsizei height) +{ + TRACE("%s(glctx: %p, x: %d, y: %d, width: %d, height: %d\n", + __FUNCTION__, glctx, x, y, width, height); + struct hgl_context *context = (struct hgl_context*)glctx->DriverCtx; + + int32 w, h; + get_bitmap_size(context->bitmap, &w, &h); + + #if 0 + // TODO: mesa_resize_framebuffer? Need to investigate where this went + if (context->draw) + st_resize_framebuffer(context->draw->stfb, w, h); + if (context->read) + st_resize_framebuffer(context->read->stfb, w, h); + #endif +} +#endif + + +static void +hgl_fill_st_visual(st_visual* stVisual, gl_config* glVisual) +{ + memset(stVisual, 0, sizeof(*stVisual)); + + // Determine color format + if (glVisual->redBits == 8) { + if (glVisual->alphaBits == 8) + stVisual->color_format = PIPE_FORMAT_B8G8R8A8_UNORM; + else + stVisual->color_format = PIPE_FORMAT_B8G8R8X8_UNORM; + } else { + stVisual->color_format = PIPE_FORMAT_B5G6R5_UNORM; + } + + // Determine depth stencil format + switch (glVisual->depthBits) { + default: + case 0: + stVisual->depth_stencil_format = PIPE_FORMAT_NONE; + break; + case 16: + stVisual->depth_stencil_format = PIPE_FORMAT_Z16_UNORM; + break; + case 24: + if (glVisual->stencilBits == 0) { + stVisual->depth_stencil_format = PIPE_FORMAT_Z24X8_UNORM; + // or PIPE_FORMAT_X8Z24_UNORM? + } else { + stVisual->depth_stencil_format = PIPE_FORMAT_Z24_UNORM_S8_UINT; + // or PIPE_FORMAT_S8_UINT_Z24_UNORM? + } + break; + case 32: + stVisual->depth_stencil_format = PIPE_FORMAT_Z32_UNORM; + break; + } + + stVisual->accum_format = (glVisual->haveAccumBuffer) + ? PIPE_FORMAT_R16G16B16A16_SNORM : PIPE_FORMAT_NONE; + + stVisual->buffer_mask |= ST_ATTACHMENT_FRONT_LEFT_MASK; + stVisual->render_buffer = ST_ATTACHMENT_FRONT_LEFT; + if (glVisual->doubleBufferMode) { + stVisual->buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK; + stVisual->render_buffer = ST_ATTACHMENT_BACK_LEFT; + } + + if (glVisual->stereoMode) { + stVisual->buffer_mask |= ST_ATTACHMENT_FRONT_RIGHT_MASK; + if (glVisual->doubleBufferMode) + stVisual->buffer_mask |= ST_ATTACHMENT_BACK_RIGHT_MASK; + } + + if (glVisual->haveDepthBuffer || glVisual->haveStencilBuffer) + stVisual->buffer_mask |= ST_ATTACHMENT_DEPTH_STENCIL_MASK; +} + + +static INLINE unsigned +round_up(unsigned n, unsigned multiple) +{ + return (n + multiple - 1) & ~(multiple - 1); +} + +/* winsys hooks */ + + +static void +hook_winsys_destroy(struct sw_winsys* winsys) +{ + CALLED(); + FREE(winsys); +} + + +static boolean +hook_winsys_is_displaytarget_format_supported(struct sw_winsys* winsys, + unsigned tex_usage, enum pipe_format format) +{ + CALLED(); + // TODO STUB + return false; +} + + +static struct sw_displaytarget* +hook_winsys_displaytarget_create(struct sw_winsys* winsys, unsigned tex_usage, + enum pipe_format format, unsigned width, unsigned height, + unsigned alignment, unsigned* stride) +{ + CALLED(); + // TODO STUB + return NULL; +} + + +static struct sw_displaytarget* +hook_winsys_displaytarget_from_handle(struct sw_winsys* winsys, + const struct pipe_resource* templat, struct winsys_handle* whandle, + unsigned* stride) +{ + CALLED(); + // TODO STUB + return NULL; +} + + +static boolean +hook_winsys_displaytarget_get_handle(struct sw_winsys* winsys, + struct sw_displaytarget* disptarget, struct winsys_handle* whandle) +{ + CALLED(); + // TODO STUB + return false; +} + + +static void* +hook_winsys_displaytarget_map(struct sw_winsys* winsys, + struct sw_displaytarget* disptarget, unsigned flags) +{ + CALLED(); + // TODO STUB + return NULL; +} + + +static void +hook_winsys_displaytarget_unmap(struct sw_winsys* winsys, + struct sw_displaytarget* disptarget) +{ + CALLED(); + // TODO STUB +} + + +static void +hook_winsys_displaytarget_display(struct sw_winsys* winsys, + struct sw_displaytarget* disptarget, void* context_private) +{ + CALLED(); + // TODO STUB +} + + +static void +hook_winsys_displaytarget_destroy(struct sw_winsys* winsys, + struct sw_displaytarget* disptarget) +{ + CALLED(); + // TODO STUB +} + + +GalliumContext::GalliumContext(ulong options) + : + fOptions(options), + fCurrentContext(0), + fScreen(NULL) +{ + CALLED(); + + CreateScreen(); + + pipe_mutex_init(fMutex); +} + + +GalliumContext::~GalliumContext() +{ + CALLED(); + + pipe_mutex_lock(fMutex); + uint32 i; + for (i = 0; i < CONTEXT_MAX; i++) { + // TODO: Delete each context + //if (fContext[i]) + // hsp_delete_context(i + 1); + } + pipe_mutex_unlock(fMutex); + + pipe_mutex_destroy(fMutex); +} + + +status_t +GalliumContext::CreateScreen() +{ + CALLED(); + + struct sw_winsys* winsys = CALLOC_STRUCT(sw_winsys); + + if (!winsys) { + ERROR("%s: Couldn't alloc sw_winsys!\n", __FUNCTION__); + return B_ERROR; + } + + // Attach winsys hooks for Haiku + // gdi_create_sw_winsys is a good Mesa example + winsys->destroy = hook_winsys_destroy; + winsys->is_displaytarget_format_supported + = hook_winsys_is_displaytarget_format_supported; + winsys->displaytarget_create = hook_winsys_displaytarget_create; + winsys->displaytarget_from_handle = hook_winsys_displaytarget_from_handle; + winsys->displaytarget_get_handle = hook_winsys_displaytarget_get_handle; + winsys->displaytarget_map = hook_winsys_displaytarget_map; + winsys->displaytarget_unmap = hook_winsys_displaytarget_unmap; + winsys->displaytarget_display = hook_winsys_displaytarget_display; + winsys->displaytarget_destroy = hook_winsys_displaytarget_destroy; + + #if USE_LLVMPIPE + fScreen = llvmpipe_create_screen(winsys); + #endif + + if (fScreen == NULL) + fScreen = softpipe_create_screen(winsys); + + if (fScreen == NULL) { + ERROR("%s: Couldn't create screen!\n", __FUNCTION__); + FREE(winsys); + return B_ERROR; + } + + const char* driverName = fScreen->get_name(fScreen); + TRACE("%s: Using %s driver.\n", __func__, driverName); + + return B_OK; +} + + +context_id +GalliumContext::CreateContext(Bitmap *bitmap) +{ + CALLED(); + + struct hgl_context* context = CALLOC_STRUCT(hgl_context); + + if (!context) { + ERROR("%s: Couldn't create pipe context!\n", __FUNCTION__); + return 0; + } + + // Set up the initial things out context needs + context->bitmap = bitmap; + context->colorSpace = get_bitmap_color_space(bitmap); + context->draw = NULL; + context->read = NULL; + context->st = NULL; + + context->api = st_gl_api_create(); + if (!context->api) { + ERROR("%s: Couldn't obtain Mesa state tracker API!\n", __func__); + return -1; + } + + context->manager = CALLOC_STRUCT(st_manager); + if (!context->manager) { + ERROR("%s: Couldn't allocate Mesa state tracker manager!\n", __func__); + return -1; + } + + // Calculate visual configuration + const GLboolean rgbFlag = ((fOptions & BGL_INDEX) == 0); + const GLboolean alphaFlag = ((fOptions & BGL_ALPHA) == BGL_ALPHA); + const GLboolean dblFlag = ((fOptions & BGL_DOUBLE) == BGL_DOUBLE); + const GLboolean stereoFlag = false; + const GLint depth = (fOptions & BGL_DEPTH) ? 24 : 0; + const GLint stencil = (fOptions & BGL_STENCIL) ? 8 : 0; + const GLint accum = 0; // (options & BGL_ACCUM) ? 16 : 0; + const GLint red = rgbFlag ? 8 : 0; + const GLint green = rgbFlag ? 8 : 0; + const GLint blue = rgbFlag ? 8 : 0; + const GLint alpha = alphaFlag ? 8 : 0; + + TRACE("rgb :\t%d\n", (bool)rgbFlag); + TRACE("alpha :\t%d\n", (bool)alphaFlag); + TRACE("dbl :\t%d\n", (bool)dblFlag); + TRACE("stereo :\t%d\n", (bool)stereoFlag); + TRACE("depth :\t%d\n", depth); + TRACE("stencil :\t%d\n", stencil); + TRACE("accum :\t%d\n", accum); + TRACE("red :\t%d\n", red); + TRACE("green :\t%d\n", green); + TRACE("blue :\t%d\n", blue); + TRACE("alpha :\t%d\n", alpha); + + gl_config* glVisual = _mesa_create_visual(dblFlag, stereoFlag, red, green, + blue, alpha, depth, stencil, accum, accum, accum, alpha ? accum : 0, 1); + + if (!glVisual) { + ERROR("%s: Couldn't create Mesa visual!\n", __func__); + return -1; + } + + TRACE("depthBits :\t%d\n", glVisual->depthBits); + TRACE("stencilBits :\t%d\n", glVisual->stencilBits); + + // Convert Mesa calculated visual into state tracker visual + struct st_visual stVisual; + hgl_fill_st_visual(&stVisual, glVisual); + + // We need to assign the screen *before* calling st_api create_context + context->manager->screen = fScreen; + + // Build state tracker attributes + struct st_context_attribs attribs; + memset(&attribs, 0, sizeof(attribs)); + attribs.options.force_glsl_extensions_warn = false; + attribs.profile = ST_PROFILE_DEFAULT; + attribs.visual = stVisual; + attribs.major = 1; + attribs.minor = 0; + //attribs.flags |= ST_CONTEXT_FLAG_DEBUG; + + struct st_api* api = context->api; + + // Create context using state tracker api call + enum st_context_error result; + context->st = api->create_context(api, context->manager, &attribs, + &result, context->st); + + if (!context->st) { + ERROR("%s: Couldn't create mesa state tracker context!\n", + __func__); + switch (result) { + case ST_CONTEXT_SUCCESS: + ERROR("%s: State tracker error: SUCCESS?\n", __func__); + break; + case ST_CONTEXT_ERROR_NO_MEMORY: + ERROR("%s: State tracker error: NO_MEMORY\n", __func__); + break; + case ST_CONTEXT_ERROR_BAD_API: + ERROR("%s: State tracker error: BAD_API\n", __func__); + break; + case ST_CONTEXT_ERROR_BAD_VERSION: + ERROR("%s: State tracker error: BAD_VERSION\n", __func__); + break; + case ST_CONTEXT_ERROR_BAD_FLAG: + ERROR("%s: State tracker error: BAD_FLAG\n", __func__); + break; + case ST_CONTEXT_ERROR_UNKNOWN_ATTRIBUTE: + ERROR("%s: State tracker error: BAD_ATTRIBUTE\n", __func__); + break; + case ST_CONTEXT_ERROR_UNKNOWN_FLAG: + ERROR("%s: State tracker error: UNKNOWN_FLAG\n", __func__); + break; + } + + FREE(context); + return -1; + } + + assert(!context->st->st_manager_private); + context->st->st_manager_private = (void*)context; + + // TODO! + //context->st->ctx->DriverCtx = context; + //context->st->ctx->Driver.Viewport = hgl_viewport; + + // TODO: Closely review this next context logic... + context_id contextNext = -1; + + pipe_mutex_lock(fMutex); + context_id i; + for (i = 0; i < CONTEXT_MAX; i++) { + if (fContext[i] == NULL) { + fContext[i] = context; + contextNext = i; + break; + } + } + pipe_mutex_unlock(fMutex); + + if (contextNext < 0) { + ERROR("%s: The next context is invalid... something went wrong!\n", + __func__); + //st_destroy_context(context->st); + FREE(context); + _mesa_destroy_visual(glVisual); + return -1; + } + + TRACE("%s: context #%" B_PRIu64 " is the next available context\n", + __func__, contextNext); + + return contextNext; +} + + +status_t +GalliumContext::SetCurrentContext(Bitmap *bitmap, context_id contextID) +{ + CALLED(); + + if (contextID < 0 || contextID > CONTEXT_MAX) { + ERROR("%s: Invalid context ID range!\n", __func__); + return B_ERROR; + } + + pipe_mutex_lock(fMutex); + context_id oldContextID = fCurrentContext; + struct hgl_context* context = fContext[contextID]; + pipe_mutex_unlock(fMutex); + + if (!context) { + ERROR("%s: Invalid context provided (#%" B_PRIu64 ")!\n", + __func__, contextID); + return B_ERROR; + } + + struct st_api* api = context->api; + + if (!bitmap) { + ERROR("%s: Invalid bitmap provided!\n", __func__); + api->make_current(context->api, NULL, NULL, NULL); + return B_ERROR; + } + + // Everything seems valid, lets set the new context. + fCurrentContext = contextID; + + if (oldContextID > 0 && oldContextID != contextID) { + fContext[oldContextID]->st->flush(fContext[oldContextID]->st, + 0, NULL); + } + + // TODO: WinSysDrawBuffer & WinSysReadBuffer? + api->make_current(context->api, context->st, context->read, context->draw); + + + // TODO: Anything else? st_api_make_current + + context->bitmap = bitmap; + //context->st->pipe->priv = context; + + return B_OK; +} + + +status_t +GalliumContext::SwapBuffers(context_id contextID) +{ + CALLED(); + + pipe_mutex_lock(fMutex); + struct hgl_context *context = fContext[contextID]; + pipe_mutex_unlock(fMutex); + + if (!context) { + ERROR("%s: context not found\n", __func__); + return B_ERROR; + } + + //pipe_mutex_lock(context->draw->mutex); + + // TODO: Where did st_notify_swapbuffers go? + //st_notify_swapbuffers(context->draw->stfb); + + // TODO: Where did st_get_framebuffer_surface go? + //struct pipe_surface *surface; + //st_get_framebuffer_surface(context->draw->stfb, ST_SURFACE_BACK_LEFT, + // &surface); + + context->st->flush(context->st, ST_FLUSH_FRONT, NULL); + + // TODO: Flush the frontbuffer! + //hsp_dev->hsp_winsys->flush_frontbuffer(hsp_dev->screen, surface, + // context->bitmap); + + //pipe_mutex_unlock(context->draw->mutex); + + return true; +} diff --git a/src/add-ons/opengl/swpipe/GalliumContext.h b/src/add-ons/opengl/swpipe/GalliumContext.h new file mode 100644 index 00000000000..b8084d26d13 --- /dev/null +++ b/src/add-ons/opengl/swpipe/GalliumContext.h @@ -0,0 +1,75 @@ +/* + * Copyright 2009, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Alexander von Gluck IV, kallisti5@unixzen.com + */ +#ifndef CALLIUMCONTEXT_H +#define CALLIUMCONTEXT_H + + +extern "C" { +#include "state_tracker/st_api.h" +#include "pipe/p_compiler.h" +#include "pipe/p_screen.h" +#include "os/os_thread.h" +} + +#include "bitmap_wrapper.h" + + +#define CONTEXT_MAX 32 + +// HACK: offsetof must be redefined before loading sp_context.h +// in GalliumContext.cpp +#undef offsetof +#define offsetof( type, member ) ((size_t) &((type *)0)->member) + + +typedef int64 context_id; + +struct hgl_context +{ + struct st_api* api; + // State Tracker API + struct st_manager* manager; + // State Tracker Manager + struct st_context_iface* st; + // State Tracker Interface Object + + Bitmap* bitmap; + color_space colorSpace; + + struct st_framebuffer_iface* draw; + struct st_framebuffer_iface* read; +}; + + +class GalliumContext { +public: + GalliumContext(ulong options); + ~GalliumContext(); + + context_id CreateContext(Bitmap* bitmap); + context_id GetCurrentContext() { return fCurrentContext; }; + status_t SetCurrentContext(Bitmap *bitmap, + context_id contextID); + + status_t SwapBuffers(context_id contextID); + +private: + status_t CreateScreen(); + void Flush(); + + ulong fOptions; + + struct hgl_context* fContext[CONTEXT_MAX]; + context_id fCurrentContext; + + struct pipe_screen* fScreen; + pipe_mutex fMutex; +}; + + +#endif /* CALLIUMCONTEXT_H */ diff --git a/src/add-ons/opengl/swpipe/Jamfile b/src/add-ons/opengl/swpipe/Jamfile new file mode 100644 index 00000000000..fb9e7c5f7fe --- /dev/null +++ b/src/add-ons/opengl/swpipe/Jamfile @@ -0,0 +1,26 @@ +SubDir HAIKU_TOP src add-ons opengl swpipe ; + +UseHeaders [ FDirName $(HAIKU_MESA_DIR) src gallium auxiliary ] ; +UseHeaders [ FDirName $(HAIKU_MESA_DIR) src gallium drivers ] ; +UseHeaders [ FDirName $(HAIKU_MESA_DIR) src gallium include ] ; +UseHeaders [ FDirName $(HAIKU_MESA_DIR) src mapi ] ; +UseHeaders [ FDirName $(HAIKU_MESA_DIR) src mesa ] ; + +local sources = + SoftwareRenderer.cpp + GalliumContext.cpp + bitmap_wrapper.cpp ; + +UsePrivateHeaders interface ; +SubDirSysHdrs $(HAIKU_MESA_HEADERS) ; +Includes [ FGristFiles $(sources) ] : $(HAIKU_MESA_HEADERS_DEPENDENCY) ; + +#AddResources Software\ Renderer : SoftwareRenderer.rdef ; + +Addon Software\ Renderer : + $(sources) + : libGL.so + $(HAIKU_MESA_DIR)/lib.haiku/libgallium.a + $(HAIKU_MESA_DIR)/lib.haiku/libsoftpipe.a + be translation $(TARGET_LIBSUPC++) +; diff --git a/src/add-ons/opengl/swpipe/SoftwareRenderer.cpp b/src/add-ons/opengl/swpipe/SoftwareRenderer.cpp new file mode 100644 index 00000000000..09503853b81 --- /dev/null +++ b/src/add-ons/opengl/swpipe/SoftwareRenderer.cpp @@ -0,0 +1,359 @@ +/* + * Copyright 2006-2009, 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 + * Artur Wyszynski, harakash@gmail.com + * Alexander von Gluck IV, kallisti5@unixzen.com + */ + + +#include "SoftwareRenderer.h" + +#include +#include +#include +#include +#include +#include +#include + + +#define TRACE_SOFTWARE +#ifdef TRACE_SOFTWARE +# 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(); + fNewWidth = fWidth; + fNewHeight = fHeight; + + _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) { + fNewWidth = fInfo->window_bounds.right - fInfo->window_bounds.left;// + 1; + fNewHeight = fInfo->window_bounds.bottom - fInfo->window_bounds.top;// + 1; + } + + if (fBitmap && cs == fColorSpace && fNewWidth == fWidth + && fNewHeight == fHeight) { + fContextObj->SetCurrentContext(fBitmap, fContextID); + return; + } + + fColorSpace = cs; + fWidth = fNewWidth; + fHeight = fNewHeight; + + _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() + 1 + || fInfo->window_bounds.right - fInfo->window_bounds.left + != fBitmap->Bounds().IntegerWidth() + 1) { + return; + } + uint8 bytesPerPixel = fInfo->bits_per_pixel / 8; + uint32 bytesPerRow = fBitmap->BytesPerRow(); + 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) +{ +// CALLED(); + BAutolock lock(fInfoLocker); + fNewWidth = (GLuint)width; + fNewHeight = (GLuint)height; +} + + +void +SoftwareRenderer::_AllocateBitmap() +{ +// CALLED(); + + // allocate new size of back buffer bitmap + BAutolock lock(fInfoLocker); + delete fBitmap; + fBitmap = NULL; + 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 - 1, fHeight - 1); + fBitmap = new (std::nothrow) BBitmap(rect, fColorSpace); + if (fBitmap == NULL) { + TRACE("%s: Can't create bitmap!\n", __func__); + return; + } +#if 0 + // debug.. + void *data = fBitmap->Bits(); + memset(data, 0xcc, fBitmap->BitsLength()); +#endif +} diff --git a/src/add-ons/opengl/swpipe/SoftwareRenderer.h b/src/add-ons/opengl/swpipe/SoftwareRenderer.h new file mode 100644 index 00000000000..bb0066bf05b --- /dev/null +++ b/src/add-ons/opengl/swpipe/SoftwareRenderer.h @@ -0,0 +1,57 @@ +/* + * 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 + */ +#ifndef SOFTWARERENDERER_H +#define SOFTWARERENDERER_H + + +#include "GLRenderer.h" +#include "GalliumContext.h" + + +class SoftwareRenderer : public BGLRenderer { +public: + SoftwareRenderer(BGLView *view, + ulong bgl_options, + BGLDispatcher *dispatcher); + virtual ~SoftwareRenderer(); + + virtual void LockGL(); + virtual void UnlockGL(); + + virtual void SwapBuffers(bool vsync = false); + virtual void Draw(BRect updateRect); + virtual status_t CopyPixelsOut(BPoint source, BBitmap *dest); + virtual status_t CopyPixelsIn(BBitmap *source, BPoint dest); + virtual void FrameResized(float width, float height); + + virtual void EnableDirectMode(bool enabled); + virtual void DirectConnected(direct_buffer_info *info); + +private: + + void _AllocateBitmap(); + + GalliumContext* fContextObj; + BBitmap* fBitmap; + context_id fContextID; + + bool fDirectModeEnabled; + direct_buffer_info* fInfo; + BLocker fInfoLocker; + ulong fOptions; + GLuint fWidth; + GLuint fHeight; + GLuint fNewWidth; + GLuint fNewHeight; + color_space fColorSpace; +}; + +#endif // SOFTPIPERENDERER_H diff --git a/src/add-ons/opengl/swpipe/bitmap_wrapper.cpp b/src/add-ons/opengl/swpipe/bitmap_wrapper.cpp new file mode 100644 index 00000000000..10726bd6402 --- /dev/null +++ b/src/add-ons/opengl/swpipe/bitmap_wrapper.cpp @@ -0,0 +1,117 @@ +/* + * Copyright 2009, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Based on gallium gdi winsys + * + * Authors: + * Artur Wyszynski + */ + + +#include +#include +#include +#include +#include +#include +#include "bitmap_wrapper.h" + + +extern "C" { +static int frameNo = 0; + + +Bitmap* +create_bitmap(int32 width, int32 height, color_space colorSpace) +{ + BBitmap *bb = new BBitmap(BRect(0, 0, width, height), colorSpace); + if (bb) + return (Bitmap*)bb; + return NULL; +} + + +void +get_bitmap_size(const Bitmap* bitmap, int32* width, int32* height) +{ + BBitmap *bb = (BBitmap*)bitmap; + if (bb && width && height) { + uint32 w = bb->Bounds().IntegerWidth() + 1; + uint32 h = bb->Bounds().IntegerHeight() + 1; + *width = w; + *height = h; + } +} + + +color_space +get_bitmap_color_space(const Bitmap* bitmap) +{ + BBitmap *bb = (BBitmap*)bitmap; + if (bb) + return bb->ColorSpace(); + return B_NO_COLOR_SPACE; +} + + +void +copy_bitmap_bits(const Bitmap* bitmap, void* data, int32 length) +{ + BBitmap *bb = (BBitmap*)bitmap; + if (bb) { + color_space cs = bb->ColorSpace(); + bb->ImportBits(data, length, bb->BytesPerRow(), 0, cs); + } +} + + +void +delete_bitmap(Bitmap* bitmap) +{ + BBitmap *bb = (BBitmap*)bitmap; + delete bb; +} + + +int32 +get_bitmap_bytes_per_row(const Bitmap* bitmap) +{ + BBitmap *bb = (BBitmap*)bitmap; + if (bb) + return bb->BytesPerRow(); + return 0; +} + + +int32 +get_bitmap_bits_length(const Bitmap* bitmap) +{ + BBitmap *bb = (BBitmap*)bitmap; + if (bb) + return bb->BitsLength(); + return 0; +} + + +void +dump_bitmap(const Bitmap* bitmap) +{ + + BBitmap *bb = (BBitmap*)bitmap; + if (!bb) + return; + + BString filename("/boot/home/frame_"); + filename << (int32)frameNo << ".png"; + + BTranslatorRoster *roster = BTranslatorRoster::Default(); + BBitmapStream stream(bb); + BFile dump(filename, B_CREATE_FILE | B_WRITE_ONLY); + + roster->Translate(&stream, NULL, NULL, &dump, 0); + + frameNo++; +} + +} diff --git a/src/add-ons/opengl/swpipe/bitmap_wrapper.h b/src/add-ons/opengl/swpipe/bitmap_wrapper.h new file mode 100644 index 00000000000..ad103ae6889 --- /dev/null +++ b/src/add-ons/opengl/swpipe/bitmap_wrapper.h @@ -0,0 +1,42 @@ +/* + * Copyright 2009, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Based on gallium gdi winsys + * + * Authors: + * Artur Wyszynski + */ +#ifndef __BBITMAP_WRAPPER_H__ +#define __BBITMAP_WRAPPER_H__ + + +#include +#include + + +typedef void Bitmap; + +#ifdef __cplusplus +extern "C" { +#endif + + +Bitmap* create_bitmap(int32 width, int32 height, color_space colorSpace); +void copy_bitmap_bits(const Bitmap* bitmap, void* data, int32 length); + +void get_bitmap_size(const Bitmap* bitmap, int32* width, int32* height); +color_space get_bitmap_color_space(const Bitmap* bitmap); +int32 get_bitmap_bytes_per_row(const Bitmap* bitmap); +int32 get_bitmap_bits_length(const Bitmap* bitmap); + +void delete_bitmap(Bitmap* bitmap); +void dump_bitmap(const Bitmap* bitmap); + + +#ifdef __cplusplus +} +#endif + + +#endif /* __BBITMAP_WRAPPER_H__ */