1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2020 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 #ifndef DRAWTHREAD
39 static int32 HAIKU_UpdateOnce(SDL_Window *window);
40 #endif
41 
_ToBeWin(SDL_Window * window)42 static SDL_INLINE SDL_BWin *_ToBeWin(SDL_Window *window) {
43     return ((SDL_BWin*)(window->driverdata));
44 }
45 
_GetBeApp()46 static SDL_INLINE SDL_BApp *_GetBeApp() {
47     return ((SDL_BApp*)be_app);
48 }
49 
HAIKU_CreateWindowFramebuffer(_THIS,SDL_Window * window,Uint32 * format,void ** pixels,int * pitch)50 int HAIKU_CreateWindowFramebuffer(_THIS, SDL_Window * window,
51                                        Uint32 * format,
52                                        void ** pixels, int *pitch) {
53     SDL_BWin *bwin = _ToBeWin(window);
54     BScreen bscreen;
55     if(!bscreen.IsValid()) {
56         return -1;
57     }
58 
59     while(!bwin->Connected()) { snooze(100); }
60 
61     /* Make sure we have exclusive access to frame buffer data */
62     bwin->LockBuffer();
63 
64     /* format */
65     display_mode bmode;
66     bscreen.GetMode(&bmode);
67     int32 bpp = HAIKU_ColorSpaceToBitsPerPixel(bmode.space);
68     *format = HAIKU_BPPToSDLPxFormat(bpp);
69 
70     /* Create the new bitmap object */
71     BBitmap *bitmap = bwin->GetBitmap();
72 
73     if(bitmap) {
74         delete bitmap;
75     }
76     bitmap = new BBitmap(bwin->Bounds(), (color_space)bmode.space,
77             false,    /* Views not accepted */
78             true);    /* Contiguous memory required */
79 
80     if(bitmap->InitCheck() != B_OK) {
81         delete bitmap;
82         return SDL_SetError("Could not initialize back buffer!");
83     }
84 
85 
86     bwin->SetBitmap(bitmap);
87 
88     /* Set the pixel pointer */
89     *pixels = bitmap->Bits();
90 
91     /* pitch = width of window, in bytes */
92     *pitch = bitmap->BytesPerRow();
93 
94     bwin->SetBufferExists(true);
95     bwin->SetTrashBuffer(false);
96     bwin->UnlockBuffer();
97     return 0;
98 }
99 
100 
101 
HAIKU_UpdateWindowFramebuffer(_THIS,SDL_Window * window,const SDL_Rect * rects,int numrects)102 int HAIKU_UpdateWindowFramebuffer(_THIS, SDL_Window * window,
103                                       const SDL_Rect * rects, int numrects) {
104     if(!window)
105         return 0;
106 
107     SDL_BWin *bwin = _ToBeWin(window);
108 
109 #ifdef DRAWTHREAD
110     bwin->LockBuffer();
111     bwin->SetBufferDirty(true);
112     bwin->UnlockBuffer();
113 #else
114     bwin->SetBufferDirty(true);
115     HAIKU_UpdateOnce(window);
116 #endif
117 
118     return 0;
119 }
120 
HAIKU_DrawThread(void * data)121 int32 HAIKU_DrawThread(void *data) {
122     SDL_BWin *bwin = (SDL_BWin*)data;
123 
124     BScreen bscreen;
125     if(!bscreen.IsValid()) {
126         return -1;
127     }
128 
129     while(bwin->ConnectionEnabled()) {
130         if( bwin->Connected() && bwin->BufferExists() && bwin->BufferIsDirty() ) {
131             bwin->LockBuffer();
132             BBitmap *bitmap = NULL;
133             bitmap = bwin->GetBitmap();
134             int32 windowPitch = bitmap->BytesPerRow();
135             int32 bufferPitch = bwin->GetRowBytes();
136             uint8 *windowpx;
137             uint8 *bufferpx;
138 
139             int32 BPP = bwin->GetBytesPerPx();
140             int32 windowSub = bwin->GetFbX() * BPP +
141                           bwin->GetFbY() * windowPitch;
142             clipping_rect *clips = bwin->GetClips();
143             int32 numClips = bwin->GetNumClips();
144             int i, y;
145 
146             /* Blit each clipping rectangle */
147             bscreen.WaitForRetrace();
148             for(i = 0; i < numClips; ++i) {
149                 /* Get addresses of the start of each clipping rectangle */
150                 int32 width = clips[i].right - clips[i].left + 1;
151                 int32 height = clips[i].bottom - clips[i].top + 1;
152                 bufferpx = bwin->GetBufferPx() +
153                     clips[i].top * bufferPitch + clips[i].left * BPP;
154                 windowpx = (uint8*)bitmap->Bits() +
155                     clips[i].top * windowPitch + clips[i].left * BPP -
156                     windowSub;
157 
158                 /* Copy each row of pixels from the window buffer into the frame
159                    buffer */
160                 for(y = 0; y < height; ++y)
161                 {
162 
163                     if(bwin->CanTrashWindowBuffer()) {
164                         goto escape;    /* Break out before the buffer is killed */
165                     }
166 
167                     memcpy(bufferpx, windowpx, width * BPP);
168                     bufferpx += bufferPitch;
169                     windowpx += windowPitch;
170                 }
171             }
172 
173             bwin->SetBufferDirty(false);
174 escape:
175             bwin->UnlockBuffer();
176         } else {
177             snooze(16000);
178         }
179     }
180 
181     return B_OK;
182 }
183 
HAIKU_DestroyWindowFramebuffer(_THIS,SDL_Window * window)184 void HAIKU_DestroyWindowFramebuffer(_THIS, SDL_Window * window) {
185     SDL_BWin *bwin = _ToBeWin(window);
186 
187     bwin->LockBuffer();
188 
189     /* Free and clear the window buffer */
190     BBitmap *bitmap = bwin->GetBitmap();
191     delete bitmap;
192     bwin->SetBitmap(NULL);
193     bwin->SetBufferExists(false);
194     bwin->UnlockBuffer();
195 }
196 
197 
198 /*
199  * TODO:
200  * This was written to test if certain errors were caused by threading issues.
201  * The specific issues have since become rare enough that they may have been
202  * solved, but I doubt it- they were pretty sporadic before now.
203  */
204 #ifndef DRAWTHREAD
HAIKU_UpdateOnce(SDL_Window * window)205 static int32 HAIKU_UpdateOnce(SDL_Window *window) {
206     SDL_BWin *bwin = _ToBeWin(window);
207     BScreen bscreen;
208     if(!bscreen.IsValid()) {
209         return -1;
210     }
211 
212     if(bwin->ConnectionEnabled() && bwin->Connected()) {
213         bwin->LockBuffer();
214         int32 windowPitch = window->surface->pitch;
215         int32 bufferPitch = bwin->GetRowBytes();
216         uint8 *windowpx;
217         uint8 *bufferpx;
218 
219         int32 BPP = bwin->GetBytesPerPx();
220         uint8 *windowBaseAddress = (uint8*)window->surface->pixels;
221         int32 windowSub = bwin->GetFbX() * BPP +
222                           bwin->GetFbY() * windowPitch;
223         clipping_rect *clips = bwin->GetClips();
224         int32 numClips = bwin->GetNumClips();
225         int i, y;
226 
227         /* Blit each clipping rectangle */
228         bscreen.WaitForRetrace();
229         for(i = 0; i < numClips; ++i) {
230             /* Get addresses of the start of each clipping rectangle */
231             int32 width = clips[i].right - clips[i].left + 1;
232             int32 height = clips[i].bottom - clips[i].top + 1;
233             bufferpx = bwin->GetBufferPx() +
234                 clips[i].top * bufferPitch + clips[i].left * BPP;
235             windowpx = windowBaseAddress +
236                 clips[i].top * windowPitch + clips[i].left * BPP - windowSub;
237 
238             /* Copy each row of pixels from the window buffer into the frame
239                buffer */
240             for(y = 0; y < height; ++y)
241             {
242                 memcpy(bufferpx, windowpx, width * BPP);
243                 bufferpx += bufferPitch;
244                 windowpx += windowPitch;
245             }
246         }
247         bwin->UnlockBuffer();
248     }
249     return 0;
250 }
251 #endif
252 
253 #ifdef __cplusplus
254 }
255 #endif
256 
257 #endif /* SDL_VIDEO_DRIVER_HAIKU */
258 
259 /* vi: set ts=4 sw=4 expandtab: */
260