2 * Copyright 2006-2012, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Jérôme Duval, korli@users.berlios.de
7 * Philippe Houdoin, philippe.houdoin@free.fr
8 * Artur Wyszynski, harakash@gmail.com
9 * Alexander von Gluck, kallisti5@unixzen.com
13 #include <kernel/image.h>
14 #include "SoftwareRast.h"
17 #include <interface/DirectWindowPrivate.h>
18 #include <GraphicsDefs.h>
24 #include "extensions.h"
25 #include "drivers/common/driverfuncs.h"
26 #include "drivers/common/meta.h"
27 #include "main/api_exec.h"
28 #include "main/colormac.h"
29 #include "main/cpuinfo.h"
30 #include "main/buffers.h"
31 #include "main/formats.h"
32 #include "main/framebuffer.h"
33 #include "main/renderbuffer.h"
34 #include "main/version.h"
35 #include "main/vtxfmt.h"
36 #include "swrast/swrast.h"
37 #include "swrast/s_renderbuffer.h"
38 #include "swrast_setup/swrast_setup.h"
40 #include "tnl/t_context.h"
41 #include "tnl/t_pipeline.h"
46 # define TRACE(x...) printf("MesaSoftwareRast: " x)
47 # define CALLED() printf("MesaSoftwareRast: %s\n", __PRETTY_FUNCTION__)
53 #define ERROR(x...) printf("MesaSoftwareRast: " x)
57 extern const char* color_space_name(color_space space
);
60 extern "C" _EXPORT BGLRenderer
*
61 instantiate_gl_renderer(BGLView
* view
, ulong options
,
62 BGLDispatcher
* dispatcher
)
64 return new MesaSoftwareRast(view
, options
, dispatcher
);
68 MesaSoftwareRast::MesaSoftwareRast(BGLView
* view
, ulong options
,
69 BGLDispatcher
* dispatcher
)
70 : BGLRenderer(view
, options
, dispatcher
),
72 fDirectModeEnabled(false),
74 fInfoLocker("info locker"),
77 fFrontRenderBuffer(NULL
),
78 fBackRenderBuffer(NULL
),
79 fColorSpace(B_NO_COLOR_SPACE
)
83 fColorSpace
= BScreen(GLView()->Window()).ColorSpace();
85 // We force single buffering for the time being
86 options
&= ~BGL_DOUBLE
;
88 const GLboolean rgbFlag
= ((options
& BGL_INDEX
) == 0);
89 const GLboolean alphaFlag
= ((options
& BGL_ALPHA
) == BGL_ALPHA
);
90 const GLboolean dblFlag
= ((options
& BGL_DOUBLE
) == BGL_DOUBLE
);
91 const GLboolean stereoFlag
= false;
92 const GLint depth
= (options
& BGL_DEPTH
) ? 16 : 0;
93 const GLint stencil
= (options
& BGL_STENCIL
) ? 8 : 0;
94 const GLint accum
= (options
& BGL_ACCUM
) ? 16 : 0;
95 const GLint red
= rgbFlag
? 8 : 0;
96 const GLint green
= rgbFlag
? 8 : 0;
97 const GLint blue
= rgbFlag
? 8 : 0;
98 const GLint alpha
= alphaFlag
? 8 : 0;
100 fOptions
= options
; // | BGL_INDIRECT;
101 struct dd_function_table functions
;
103 fVisual
= _mesa_create_visual(dblFlag
, stereoFlag
, red
, green
,
104 blue
, alpha
, depth
, stencil
, accum
, accum
, accum
,
105 alpha
? accum
: 0, 1);
107 // Initialize device driver function table
108 _mesa_init_driver_functions(&functions
);
110 functions
.GetString
= _GetString
;
111 functions
.UpdateState
= _UpdateState
;
112 functions
.MapRenderbuffer
= _RenderBufferMap
;
113 functions
.Flush
= _Flush
;
115 // create core context
116 // We inherit gl_context to this class
117 _mesa_initialize_context(this, API_OPENGL_COMPAT
, fVisual
, NULL
,
120 /* Initialize the software rasterizer and helper modules. */
121 _swrast_CreateContext(this);
122 _vbo_CreateContext(this);
123 _tnl_CreateContext(this);
124 _swsetup_CreateContext(this);
125 _swsetup_Wakeup(this);
127 // Use default TCL pipeline
128 TNL_CONTEXT(this)->Driver
.RunPipeline
= _tnl_run_pipeline
;
130 _mesa_meta_init(this);
131 _mesa_enable_sw_extensions(this);
133 _mesa_compute_version(this);
135 _mesa_initialize_dispatch_tables(this);
136 _mesa_initialize_vbo_vtxfmt(this);
138 // create core framebuffer
139 fFrameBuffer
= _mesa_create_framebuffer(fVisual
);
140 if (fFrameBuffer
== NULL
) {
141 ERROR("%s: Unable to calloc GL FrameBuffer!\n", __func__
);
142 _mesa_destroy_visual(fVisual
);
146 // Setup front render buffer
147 fFrontRenderBuffer
= _NewRenderBuffer(true);
148 if (fFrontRenderBuffer
== NULL
) {
149 ERROR("%s: FrontRenderBuffer is requested but unallocated!\n",
151 _mesa_destroy_visual(fVisual
);
155 _mesa_add_renderbuffer(fFrameBuffer
, BUFFER_FRONT_LEFT
,
156 &fFrontRenderBuffer
->Base
);
158 // Setup back render buffer (if requested)
159 if (fVisual
->doubleBufferMode
) {
160 fBackRenderBuffer
= _NewRenderBuffer(false);
161 if (fBackRenderBuffer
== NULL
) {
162 ERROR("%s: BackRenderBuffer is requested but unallocated!\n",
164 _mesa_destroy_visual(fVisual
);
168 _mesa_add_renderbuffer(fFrameBuffer
, BUFFER_BACK_LEFT
,
169 &fBackRenderBuffer
->Base
);
172 _swrast_add_soft_renderbuffers(fFrameBuffer
, GL_FALSE
,
173 fVisual
->haveDepthBuffer
, fVisual
->haveStencilBuffer
,
174 fVisual
->haveAccumBuffer
, alphaFlag
, GL_FALSE
);
176 BRect bounds
= view
->Bounds();
177 fWidth
= (GLint
)bounds
.Width();
178 fHeight
= (GLint
)bounds
.Height();
180 // some stupid applications (Quake2) don't even think about calling LockGL()
181 // before using glGetString and its glGet*() friends...
182 // so make sure there is at least a valid context.
184 if (!_mesa_get_current_context()) {
186 // not needed, we don't have a looper yet: UnlockLooper();
191 MesaSoftwareRast::~MesaSoftwareRast()
194 _swsetup_DestroyContext(this);
195 _swrast_DestroyContext(this);
196 _tnl_DestroyContext(this);
197 _vbo_DestroyContext(this);
198 _mesa_destroy_visual(fVisual
);
199 _mesa_destroy_framebuffer(fFrameBuffer
);
200 _mesa_destroy_context(this);
210 MesaSoftwareRast::LockGL()
213 BGLRenderer::LockGL();
215 _mesa_make_current(this, fFrameBuffer
, fFrameBuffer
);
217 color_space colorSpace
= BScreen(GLView()->Window()).ColorSpace();
219 GLuint width
= fWidth
;
220 GLuint height
= fHeight
;
222 BAutolock
lock(fInfoLocker
);
223 if (fDirectModeEnabled
&& fInfo
!= NULL
) {
224 width
= fInfo
->window_bounds
.right
225 - fInfo
->window_bounds
.left
+ 1;
226 height
= fInfo
->window_bounds
.bottom
227 - fInfo
->window_bounds
.top
+ 1;
230 if (fColorSpace
!= colorSpace
) {
231 fColorSpace
= colorSpace
;
232 _SetupRenderBuffer(&fFrontRenderBuffer
->Base
, fColorSpace
);
233 if (fVisual
->doubleBufferMode
)
234 _SetupRenderBuffer(&fBackRenderBuffer
->Base
, fColorSpace
);
237 _CheckResize(width
, height
);
242 MesaSoftwareRast::UnlockGL()
245 _mesa_make_current(this, NULL
, NULL
);
246 BGLRenderer::UnlockGL();
251 MesaSoftwareRast::SwapBuffers(bool VSync
)
258 if (fVisual
->doubleBufferMode
)
259 _mesa_notifySwapBuffers(this);
261 if (!fDirectModeEnabled
|| fInfo
== NULL
) {
262 if (GLView()->LockLooperWithTimeout(1000) == B_OK
) {
263 GLView()->DrawBitmap(fBitmap
, B_ORIGIN
);
264 GLView()->UnlockLooper();
267 // TODO: Here the BGLView needs to be drawlocked.
272 BScreen
screen(GLView()->Window());
273 screen
.WaitForRetrace();
279 MesaSoftwareRast::Draw(BRect updateRect
)
282 if (fBitmap
&& (!fDirectModeEnabled
|| (fInfo
== NULL
)))
283 GLView()->DrawBitmap(fBitmap
, updateRect
, updateRect
);
288 MesaSoftwareRast::CopyPixelsOut(BPoint location
, BBitmap
* bitmap
)
291 color_space scs
= fBitmap
->ColorSpace();
292 color_space dcs
= bitmap
->ColorSpace();
294 if (scs
!= dcs
&& (scs
!= B_RGBA32
|| dcs
!= B_RGB32
)) {
295 fprintf(stderr
, "CopyPixelsOut(): incompatible color space: %s != %s\n",
296 color_space_name(scs
),
297 color_space_name(dcs
));
301 BRect sr
= fBitmap
->Bounds();
302 BRect dr
= bitmap
->Bounds();
304 sr
= sr
& dr
.OffsetBySelf(location
);
305 dr
= sr
.OffsetByCopy(-location
.x
, -location
.y
);
307 uint8
* ps
= (uint8
*)fBitmap
->Bits();
308 uint8
* pd
= (uint8
*)bitmap
->Bits();
312 for (y
= (uint32
)sr
.top
; y
<= (uint32
)sr
.bottom
; y
++) {
313 s
= (uint32
*)(ps
+ y
* fBitmap
->BytesPerRow());
314 s
+= (uint32
)sr
.left
;
316 d
= (uint32
*)(pd
+ (y
+ (uint32
)(dr
.top
- sr
.top
))
317 * bitmap
->BytesPerRow());
318 d
+= (uint32
)dr
.left
;
320 memcpy(d
, s
, dr
.IntegerWidth() * 4);
327 MesaSoftwareRast::CopyPixelsIn(BBitmap
* bitmap
, BPoint location
)
330 color_space scs
= bitmap
->ColorSpace();
331 color_space dcs
= fBitmap
->ColorSpace();
333 if (scs
!= dcs
&& (dcs
!= B_RGBA32
|| scs
!= B_RGB32
)) {
334 fprintf(stderr
, "CopyPixelsIn(): incompatible color space: %s != %s\n",
335 color_space_name(scs
),
336 color_space_name(dcs
));
340 BRect sr
= bitmap
->Bounds();
341 BRect dr
= fBitmap
->Bounds();
343 sr
= sr
& dr
.OffsetBySelf(location
);
344 dr
= sr
.OffsetByCopy(-location
.x
, -location
.y
);
346 uint8
* ps
= (uint8
*)bitmap
->Bits();
347 uint8
* pd
= (uint8
*)fBitmap
->Bits();
351 for (y
= (uint32
)sr
.top
; y
<= (uint32
)sr
.bottom
; y
++) {
352 s
= (uint32
*)(ps
+ y
* bitmap
->BytesPerRow());
353 s
+= (uint32
)sr
.left
;
355 d
= (uint32
*)(pd
+ (y
+ (uint32
)(dr
.top
- sr
.top
))
356 * fBitmap
->BytesPerRow());
357 d
+= (uint32
)dr
.left
;
359 memcpy(d
, s
, dr
.IntegerWidth() * 4);
366 MesaSoftwareRast::EnableDirectMode(bool enabled
)
368 fDirectModeEnabled
= enabled
;
373 MesaSoftwareRast::DirectConnected(direct_buffer_info
* info
)
375 // TODO: I'm not sure we need to do this: BGLView already
376 // keeps a local copy of the direct_buffer_info passed by
377 // BDirectWindow::DirectConnected().
378 BAutolock
lock(fInfoLocker
);
381 fInfo
= (direct_buffer_info
*)malloc(DIRECT_BUFFER_INFO_AREA_SIZE
);
385 memcpy(fInfo
, info
, DIRECT_BUFFER_INFO_AREA_SIZE
);
394 MesaSoftwareRast::FrameResized(float width
, float height
)
396 BAutolock
lock(fInfoLocker
);
397 _CheckResize((GLuint
)width
, (GLuint
)height
);
402 MesaSoftwareRast::_CheckResize(GLuint newWidth
, GLuint newHeight
)
406 if (fBitmap
&& newWidth
== fWidth
407 && newHeight
== fHeight
) {
411 _mesa_resize_framebuffer(this, fFrameBuffer
, newWidth
, newHeight
);
420 MesaSoftwareRast::_AllocateBitmap()
424 // allocate new size of back buffer bitmap
428 if (fWidth
< 1 || fHeight
< 1) {
429 TRACE("%s: Cannot allocate bitmap < 1x1!\n", __func__
);
433 BRect
rect(0.0, 0.0, fWidth
- 1, fHeight
- 1);
434 fBitmap
= new BBitmap(rect
, fColorSpace
);
437 // Used for platform optimized drawing
438 for (uint i
= 0; i
< fHeight
; i
++) {
439 fRowAddr
[fHeight
- i
- 1] = (GLvoid
*)((GLubyte
*)fBitmap
->Bits()
440 + i
* fBitmap
->BytesPerRow());
444 fFrameBuffer
->Width
= fWidth
;
445 fFrameBuffer
->Height
= fHeight
;
446 TRACE("%s: Bitmap Size: %" B_PRIu32
"\n", __func__
, fBitmap
->BitsLength());
448 fFrontRenderBuffer
->Buffer
= (GLubyte
*)fBitmap
->Bits();
452 // #pragma mark - static
456 MesaSoftwareRast::_GetString(gl_context
* ctx
, GLenum name
)
460 return (const GLubyte
*) "Mesa Project";
462 return (const GLubyte
*) "Software Rasterizer";
464 // Let core library handle all other cases
471 MesaSoftwareRast::_UpdateState(gl_context
* ctx
, GLuint new_state
)
477 _swrast_InvalidateState(ctx
, new_state
);
478 _swsetup_InvalidateState(ctx
, new_state
);
479 _vbo_InvalidateState(ctx
, new_state
);
480 _tnl_InvalidateState(ctx
, new_state
);
485 MesaSoftwareRast::_RenderBufferStorage(gl_context
* ctx
,
486 struct gl_renderbuffer
* render
, GLenum internalFormat
,
487 GLuint width
, GLuint height
)
491 render
->Width
= width
;
492 render
->Height
= height
;
494 struct swrast_renderbuffer
*swRenderBuffer
= swrast_renderbuffer(render
);
496 swRenderBuffer
->RowStride
= width
* _mesa_get_format_bytes(render
->Format
);
503 MesaSoftwareRast::_RenderBufferStorageMalloc(gl_context
* ctx
,
504 struct gl_renderbuffer
* render
, GLenum internalFormat
,
505 GLuint width
, GLuint height
)
509 render
->Width
= width
;
510 render
->Height
= height
;
512 struct swrast_renderbuffer
*swRenderBuffer
= swrast_renderbuffer(render
);
514 if (swRenderBuffer
!= NULL
) {
515 free(swRenderBuffer
->Buffer
);
516 swRenderBuffer
->RowStride
517 = width
* _mesa_get_format_bytes(render
->Format
);
519 uint32 size
= swRenderBuffer
->RowStride
* height
;
520 TRACE("%s: Allocate %" B_PRIu32
" bytes for RenderBuffer\n",
522 swRenderBuffer
->Buffer
= (GLubyte
*)malloc(size
);
523 if (!swRenderBuffer
->Buffer
) {
524 ERROR("%s: Memory allocation failure!\n", __func__
);
528 ERROR("%s: Couldn't obtain software renderbuffer!\n",
538 MesaSoftwareRast::_Flush(gl_context
* ctx
)
541 MesaSoftwareRast
* driverContext
= static_cast<MesaSoftwareRast
*>(ctx
);
543 //MesaSoftwareRast* driverContext = (MesaSoftwareRast*)ctx->DriverCtx;
544 if ((driverContext
->fOptions
& BGL_DOUBLE
) == 0) {
545 // TODO: SwapBuffers() can call _CopyToDirect(), which should
546 // be always called with with the BGLView drawlocked.
547 // This is not always the case if called from here.
548 driverContext
->SwapBuffers();
553 struct swrast_renderbuffer
*
554 MesaSoftwareRast::_NewRenderBuffer(bool front
)
557 struct swrast_renderbuffer
*swRenderBuffer
558 = (struct swrast_renderbuffer
*)calloc(1, sizeof *swRenderBuffer
);
560 if (!swRenderBuffer
) {
561 ERROR("%s: Failed calloc RenderBuffer\n", __func__
);
565 _mesa_init_renderbuffer(&swRenderBuffer
->Base
, 0);
567 swRenderBuffer
->Base
.ClassID
= HAIKU_SWRAST_RENDERBUFFER_CLASS
;
568 swRenderBuffer
->Base
.RefCount
= 1;
569 swRenderBuffer
->Base
.Delete
= _RenderBufferDelete
;
572 swRenderBuffer
->Base
.AllocStorage
= _RenderBufferStorageMalloc
;
574 swRenderBuffer
->Base
.AllocStorage
= _RenderBufferStorage
;
576 if (_SetupRenderBuffer(&swRenderBuffer
->Base
, fColorSpace
) != B_OK
) {
577 free(swRenderBuffer
);
581 return swRenderBuffer
;
586 MesaSoftwareRast::_SetupRenderBuffer(struct gl_renderbuffer
* rb
,
587 color_space colorSpace
)
591 rb
->InternalFormat
= GL_RGBA
;
593 switch (colorSpace
) {
595 rb
->_BaseFormat
= GL_RGBA
;
596 rb
->Format
= MESA_FORMAT_B8G8R8A8_UNORM
;
599 rb
->_BaseFormat
= GL_RGB
;
600 rb
->Format
= MESA_FORMAT_B8G8R8X8_UNORM
;
603 rb
->_BaseFormat
= GL_RGB
;
604 rb
->Format
= MESA_FORMAT_RGB888
;
607 rb
->_BaseFormat
= GL_RGB
;
608 rb
->Format
= MESA_FORMAT_RGB565
;
611 rb
->_BaseFormat
= GL_RGB
;
612 rb
->Format
= MESA_FORMAT_ARGB1555
;
615 fprintf(stderr
, "Unsupported screen color space %s\n",
616 color_space_name(fColorSpace
));
617 debugger("Unsupported OpenGL color space");
624 /*! Y inverted Map RenderBuffer function
625 We use a BBitmap for storage which has Y inverted.
626 If the Mesa provided Map function ever allows external
627 control of this we can omit this function.
630 MesaSoftwareRast::_RenderBufferMap(gl_context
*ctx
,
631 struct gl_renderbuffer
*rb
, GLuint x
, GLuint y
, GLuint w
, GLuint h
,
632 GLbitfield mode
, GLubyte
**mapOut
, GLint
*rowStrideOut
)
634 if (rb
->ClassID
== HAIKU_SWRAST_RENDERBUFFER_CLASS
) {
635 struct swrast_renderbuffer
*srb
= swrast_renderbuffer(rb
);
636 const GLuint bpp
= _mesa_get_format_bytes(rb
->Format
);
637 GLint rowStride
= rb
->Width
* bpp
; // in Bytes
639 y
= rb
->Height
- y
- 1;
641 *rowStrideOut
= -rowStride
;
642 *mapOut
= (GLubyte
*) srb
->Buffer
+ y
* rowStride
+ x
* bpp
;
644 _swrast_map_soft_renderbuffer(ctx
, rb
, x
, y
, w
, h
, mode
,
645 mapOut
, rowStrideOut
);
651 MesaSoftwareRast::_RenderBufferDelete(struct gl_context
*ctx
,
652 struct gl_renderbuffer
* rb
)
656 struct swrast_renderbuffer
*swRenderBuffer
657 = swrast_renderbuffer(rb
);
658 if (swRenderBuffer
!= NULL
)
659 free(swRenderBuffer
->Buffer
);
666 MesaSoftwareRast::_CopyToDirect()
668 BAutolock
lock(fInfoLocker
);
670 // check the bitmap size still matches the size
671 if (fInfo
->window_bounds
.bottom
- fInfo
->window_bounds
.top
672 != fBitmap
->Bounds().IntegerHeight()
673 || fInfo
->window_bounds
.right
- fInfo
->window_bounds
.left
674 != fBitmap
->Bounds().IntegerWidth())
677 uint8 bytesPerPixel
= fInfo
->bits_per_pixel
/ 8;
678 uint32 bytesPerRow
= fBitmap
->BytesPerRow();
679 for (uint32 i
= 0; i
< fInfo
->clip_list_count
; i
++) {
680 clipping_rect
*clip
= &fInfo
->clip_list
[i
];
681 int32 height
= clip
->bottom
- clip
->top
+ 1;
683 = (clip
->right
- clip
->left
+ 1) * bytesPerPixel
;
684 uint8
* p
= (uint8
*)fInfo
->bits
+ clip
->top
685 * fInfo
->bytes_per_row
+ clip
->left
* bytesPerPixel
;
686 uint8
* b
= (uint8
*)fBitmap
->Bits()
687 + (clip
->top
- fInfo
->window_bounds
.top
) * bytesPerRow
688 + (clip
->left
- fInfo
->window_bounds
.left
)
691 for (int y
= 0; y
< height
; y
++) {
692 memcpy(p
, b
, bytesWidth
);
693 p
+= fInfo
->bytes_per_row
;