1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22
23 #if SDL_VIDEO_DRIVER_HAIKU
24
25 #include "SDL_bframebuffer.h"
26
27 #include <AppKit.h>
28 #include <InterfaceKit.h>
29 #include "SDL_bmodes.h"
30 #include "SDL_BWin.h"
31
32 #include "../../main/haiku/SDL_BApp.h"
33
34 #ifdef __cplusplus
35 extern "C" {
36 #endif
37
38 int32 BE_UpdateOnce(SDL_Window *window);
39
_ToBeWin(SDL_Window * window)40 static SDL_INLINE SDL_BWin *_ToBeWin(SDL_Window *window) {
41 return ((SDL_BWin*)(window->driverdata));
42 }
43
_GetBeApp()44 static SDL_INLINE SDL_BApp *_GetBeApp() {
45 return ((SDL_BApp*)be_app);
46 }
47
BE_CreateWindowFramebuffer(_THIS,SDL_Window * window,Uint32 * format,void ** pixels,int * pitch)48 int BE_CreateWindowFramebuffer(_THIS, SDL_Window * window,
49 Uint32 * format,
50 void ** pixels, int *pitch) {
51 SDL_BWin *bwin = _ToBeWin(window);
52 BScreen bscreen;
53 if(!bscreen.IsValid()) {
54 return -1;
55 }
56
57 while(!bwin->Connected()) { snooze(100); }
58
59 /* Make sure we have exclusive access to frame buffer data */
60 bwin->LockBuffer();
61
62 /* format */
63 display_mode bmode;
64 bscreen.GetMode(&bmode);
65 int32 bpp = BE_ColorSpaceToBitsPerPixel(bmode.space);
66 *format = BE_BPPToSDLPxFormat(bpp);
67
68 /* Create the new bitmap object */
69 BBitmap *bitmap = bwin->GetBitmap();
70
71 if(bitmap) {
72 delete bitmap;
73 }
74 bitmap = new BBitmap(bwin->Bounds(), (color_space)bmode.space,
75 false, /* Views not accepted */
76 true); /* Contiguous memory required */
77
78 if(bitmap->InitCheck() != B_OK) {
79 return SDL_SetError("Could not initialize back buffer!\n");
80 }
81
82
83 bwin->SetBitmap(bitmap);
84
85 /* Set the pixel pointer */
86 *pixels = bitmap->Bits();
87
88 /* pitch = width of window, in bytes */
89 *pitch = bitmap->BytesPerRow();
90
91 bwin->SetBufferExists(true);
92 bwin->SetTrashBuffer(false);
93 bwin->UnlockBuffer();
94 return 0;
95 }
96
97
98
BE_UpdateWindowFramebuffer(_THIS,SDL_Window * window,const SDL_Rect * rects,int numrects)99 int BE_UpdateWindowFramebuffer(_THIS, SDL_Window * window,
100 const SDL_Rect * rects, int numrects) {
101 if(!window)
102 return 0;
103
104 SDL_BWin *bwin = _ToBeWin(window);
105
106 #ifdef DRAWTHREAD
107 bwin->LockBuffer();
108 bwin->SetBufferDirty(true);
109 bwin->UnlockBuffer();
110 #else
111 bwin->SetBufferDirty(true);
112 BE_UpdateOnce(window);
113 #endif
114
115 return 0;
116 }
117
BE_DrawThread(void * data)118 int32 BE_DrawThread(void *data) {
119 SDL_BWin *bwin = (SDL_BWin*)data;
120
121 BScreen bscreen;
122 if(!bscreen.IsValid()) {
123 return -1;
124 }
125
126 while(bwin->ConnectionEnabled()) {
127 if( bwin->Connected() && bwin->BufferExists() && bwin->BufferIsDirty() ) {
128 bwin->LockBuffer();
129 BBitmap *bitmap = NULL;
130 bitmap = bwin->GetBitmap();
131 int32 windowPitch = bitmap->BytesPerRow();
132 int32 bufferPitch = bwin->GetRowBytes();
133 uint8 *windowpx;
134 uint8 *bufferpx;
135
136 int32 BPP = bwin->GetBytesPerPx();
137 int32 windowSub = bwin->GetFbX() * BPP +
138 bwin->GetFbY() * windowPitch;
139 clipping_rect *clips = bwin->GetClips();
140 int32 numClips = bwin->GetNumClips();
141 int i, y;
142
143 /* Blit each clipping rectangle */
144 bscreen.WaitForRetrace();
145 for(i = 0; i < numClips; ++i) {
146 clipping_rect rc = clips[i];
147 /* Get addresses of the start of each clipping rectangle */
148 int32 width = clips[i].right - clips[i].left + 1;
149 int32 height = clips[i].bottom - clips[i].top + 1;
150 bufferpx = bwin->GetBufferPx() +
151 clips[i].top * bufferPitch + clips[i].left * BPP;
152 windowpx = (uint8*)bitmap->Bits() +
153 clips[i].top * windowPitch + clips[i].left * BPP -
154 windowSub;
155
156 /* Copy each row of pixels from the window buffer into the frame
157 buffer */
158 for(y = 0; y < height; ++y)
159 {
160
161 if(bwin->CanTrashWindowBuffer()) {
162 goto escape; /* Break out before the buffer is killed */
163 }
164
165 memcpy(bufferpx, windowpx, width * BPP);
166 bufferpx += bufferPitch;
167 windowpx += windowPitch;
168 }
169 }
170
171 bwin->SetBufferDirty(false);
172 escape:
173 bwin->UnlockBuffer();
174 } else {
175 snooze(16000);
176 }
177 }
178
179 return B_OK;
180 }
181
BE_DestroyWindowFramebuffer(_THIS,SDL_Window * window)182 void BE_DestroyWindowFramebuffer(_THIS, SDL_Window * window) {
183 SDL_BWin *bwin = _ToBeWin(window);
184
185 bwin->LockBuffer();
186
187 /* Free and clear the window buffer */
188 BBitmap *bitmap = bwin->GetBitmap();
189 delete bitmap;
190 bwin->SetBitmap(NULL);
191 bwin->SetBufferExists(false);
192 bwin->UnlockBuffer();
193 }
194
195
196 /*
197 * TODO:
198 * This was written to test if certain errors were caused by threading issues.
199 * The specific issues have since become rare enough that they may have been
200 * solved, but I doubt it- they were pretty sporadic before now.
201 */
BE_UpdateOnce(SDL_Window * window)202 int32 BE_UpdateOnce(SDL_Window *window) {
203 SDL_BWin *bwin = _ToBeWin(window);
204 BScreen bscreen;
205 if(!bscreen.IsValid()) {
206 return -1;
207 }
208
209 if(bwin->ConnectionEnabled() && bwin->Connected()) {
210 bwin->LockBuffer();
211 int32 windowPitch = window->surface->pitch;
212 int32 bufferPitch = bwin->GetRowBytes();
213 uint8 *windowpx;
214 uint8 *bufferpx;
215
216 int32 BPP = bwin->GetBytesPerPx();
217 uint8 *windowBaseAddress = (uint8*)window->surface->pixels;
218 int32 windowSub = bwin->GetFbX() * BPP +
219 bwin->GetFbY() * windowPitch;
220 clipping_rect *clips = bwin->GetClips();
221 int32 numClips = bwin->GetNumClips();
222 int i, y;
223
224 /* Blit each clipping rectangle */
225 bscreen.WaitForRetrace();
226 for(i = 0; i < numClips; ++i) {
227 clipping_rect rc = clips[i];
228 /* Get addresses of the start of each clipping rectangle */
229 int32 width = clips[i].right - clips[i].left + 1;
230 int32 height = clips[i].bottom - clips[i].top + 1;
231 bufferpx = bwin->GetBufferPx() +
232 clips[i].top * bufferPitch + clips[i].left * BPP;
233 windowpx = windowBaseAddress +
234 clips[i].top * windowPitch + clips[i].left * BPP - windowSub;
235
236 /* Copy each row of pixels from the window buffer into the frame
237 buffer */
238 for(y = 0; y < height; ++y)
239 {
240 memcpy(bufferpx, windowpx, width * BPP);
241 bufferpx += bufferPitch;
242 windowpx += windowPitch;
243 }
244 }
245 bwin->UnlockBuffer();
246 }
247 return 0;
248 }
249
250 #ifdef __cplusplus
251 }
252 #endif
253
254 #endif /* SDL_VIDEO_DRIVER_HAIKU */
255