Extrenal srt problem gst-1 solved.
[openblackhole/openblackhole-enigma2.git] / lib / gdi / accel.cpp
1 #include <cstring>
2 #include <lib/base/init.h>
3 #include <lib/base/init_num.h>
4 #include <lib/gdi/accel.h>
5 #include <lib/base/eerror.h>
6 #include <lib/gdi/esize.h>
7 #include <lib/gdi/epoint.h>
8 #include <lib/gdi/erect.h>
9 #include <lib/gdi/gpixmap.h>
10
11 /* Apparently, surfaces must be 64-byte aligned */
12 #define ACCEL_ALIGNMENT_SHIFT   6
13 #define ACCEL_ALIGNMENT_MASK    ((1<<ACCEL_ALIGNMENT_SHIFT)-1)
14
15 // #define ACCEL_DEBUG
16
17 gAccel *gAccel::instance;
18 #define BCM_ACCEL
19
20 #ifdef ATI_ACCEL
21 extern int ati_accel_init(void);
22 extern void ati_accel_close(void);
23 extern void ati_accel_blit(
24                 int src_addr, int src_width, int src_height, int src_stride,
25                 int dst_addr, int dst_width, int dst_height, int dst_stride,
26                 int src_x, int src_y, int width, int height,
27                 int dst_x, int dst_y);
28 extern void ati_accel_fill(
29                 int dst_addr, int dst_width, int dst_height, int dst_stride,
30                 int x, int y, int width, int height,
31                 unsigned long color);
32 #endif
33 #ifdef BCM_ACCEL
34 extern int bcm_accel_init(void);
35 extern void bcm_accel_close(void);
36 extern void bcm_accel_blit(
37                 int src_addr, int src_width, int src_height, int src_stride, int src_format,
38                 int dst_addr, int dst_width, int dst_height, int dst_stride,
39                 int src_x, int src_y, int width, int height,
40                 int dst_x, int dst_y, int dwidth, int dheight,
41                 int pal_addr, int flags);
42 extern void bcm_accel_fill(
43                 int dst_addr, int dst_width, int dst_height, int dst_stride,
44                 int x, int y, int width, int height,
45                 unsigned long color);
46 extern bool bcm_accel_has_alphablending();
47 #endif
48
49 gAccel::gAccel():
50         m_accel_addr(0),
51         m_accel_phys_addr(0),
52         m_accel_size(0)
53 {
54         instance = this;
55
56 #ifdef ATI_ACCEL
57         ati_accel_init();
58 #endif
59 #ifdef BCM_ACCEL
60         m_bcm_accel_state = bcm_accel_init();
61 #endif
62 }
63
64 gAccel::~gAccel()
65 {
66 #ifdef ATI_ACCEL
67         ati_accel_close();
68 #endif
69 #ifdef BCM_ACCEL
70         bcm_accel_close();
71 #endif
72         instance = 0;
73 }
74
75 #ifdef ACCEL_DEBUG
76 void gAccel::dumpDebug()
77 {
78         eDebug("[gAccel] info --");
79         for (MemoryBlockList::const_iterator it = m_accel_allocation.begin();
80                  it != m_accel_allocation.end();
81                  ++it)
82          {
83                  gUnmanagedSurface *surface = it->surface;
84                  if (surface)
85                         eDebug("[gAccel] surface: (%d (%dk), %d (%dk)) %p %dx%d:%d",
86                                         it->index, it->index >> (10 - ACCEL_ALIGNMENT_SHIFT),
87                                         it->size, it->size >> (10 - ACCEL_ALIGNMENT_SHIFT),
88                                         surface, surface->stride, surface->y, surface->bpp);
89                 else
90                         eDebug("[gAccel]    free: (%d (%dk), %d (%dk))",
91                                         it->index, it->index >> (10 - ACCEL_ALIGNMENT_SHIFT),
92                                         it->size, it->size >> (10 - ACCEL_ALIGNMENT_SHIFT));
93          }
94         eDebug("--");
95 }
96 #else
97 void gAccel::dumpDebug() {}
98 #endif
99
100 void gAccel::releaseAccelMemorySpace()
101 {
102         eSingleLocker lock(m_allocation_lock);
103         dumpDebug();
104         for (MemoryBlockList::const_iterator it = m_accel_allocation.begin();
105                  it != m_accel_allocation.end();
106                  ++it)
107         {
108                 gUnmanagedSurface *surface = it->surface;
109                 if (surface != NULL)
110                 {
111                         int size = surface->y * surface->stride;
112 #ifdef ACCEL_DEBUG
113                         eDebug("[gAccel] %s: Re-locating %p->%x(%p) %dx%d:%d", __func__, surface, surface->data_phys, surface->data, surface->x, surface->y, surface->bpp);
114 #endif
115                         unsigned char *new_data = new unsigned char [size];
116                         memcpy(new_data, surface->data, size);
117                         surface->data = new_data;
118                         surface->data_phys = 0;
119                 }
120         }
121         m_accel_allocation.clear();
122         m_accel_size = 0;
123 }
124
125 void gAccel::setAccelMemorySpace(void *addr, int phys_addr, int size)
126 {
127         if (size > 0)
128         {
129                 eSingleLocker lock(m_allocation_lock);
130                 m_accel_size = size >> ACCEL_ALIGNMENT_SHIFT;
131                 m_accel_addr = addr;
132                 m_accel_phys_addr = phys_addr;
133                 m_accel_allocation.push_back(MemoryBlock(NULL, 0, m_accel_size));
134                 dumpDebug();
135         }
136 }
137
138 bool gAccel::hasAlphaBlendingSupport()
139 {
140 #ifdef BCM_ACCEL
141         return bcm_accel_has_alphablending();
142 #else
143         return false;
144 #endif
145 }
146
147 int gAccel::blit(gUnmanagedSurface *dst, gUnmanagedSurface *src, const eRect &p, const eRect &area, int flags)
148 {
149 #ifdef ATI_ACCEL
150         ati_accel_blit(
151                 src->data_phys, src->x, src->y, src->stride,
152                 dst->data_phys, dst->x, dst->y, dst->stride,
153                 area.left(), area.top(), area.width(), area.height(),
154                 p.x(), p.y());
155         return 0;
156 #endif
157 #ifdef BCM_ACCEL
158         if (!m_bcm_accel_state)
159         {
160                 unsigned long pal_addr = 0;
161                 int src_format = 0;
162                 if (src->bpp == 32)
163                         src_format = 0;
164                 else if ((src->bpp == 8) && src->clut.data)
165                 {
166                         src_format = 1;
167                         /* sync pal */
168                         if (src->clut.data_phys == 0)
169                         {
170                                 /* sync pal */
171                                 pal_addr = src->stride * src->y;
172                                 unsigned long *pal = (unsigned long*)(((unsigned char*)src->data) + pal_addr);
173                                 pal_addr += src->data_phys;
174                                 for (int i = 0; i < src->clut.colors; ++i)
175                                         *pal++ = src->clut.data[i].argb() ^ 0xFF000000;
176                                 src->clut.data_phys = pal_addr;
177                         }
178                         else
179                         {
180                                 pal_addr = src->clut.data_phys;
181                         }
182                 } else
183                         return -1; /* unsupported source format */
184
185                 bcm_accel_blit(
186                         src->data_phys, src->x, src->y, src->stride, src_format,
187                         dst->data_phys, dst->x, dst->y, dst->stride,
188                         area.left(), area.top(), area.width(), area.height(),
189                         p.x(), p.y(), p.width(), p.height(),
190                         pal_addr, flags);
191                 return 0;
192         }
193 #endif
194         return -1;
195 }
196
197 int gAccel::fill(gUnmanagedSurface *dst, const eRect &area, unsigned long col)
198 {
199 #ifdef FORCE_NO_FILL_ACCELERATION
200         return -1;
201 #endif
202 #ifdef ATI_ACCEL
203         ati_accel_fill(
204                 dst->data_phys, dst->x, dst->y, dst->stride,
205                 area.left(), area.top(), area.width(), area.height(),
206                 col);
207         return 0;
208 #endif
209 #ifdef BCM_ACCEL
210         if (!m_bcm_accel_state) {
211                 bcm_accel_fill(
212                         dst->data_phys, dst->x, dst->y, dst->stride,
213                         area.left(), area.top(), area.width(), area.height(),
214                         col);
215                 return 0;
216         }
217 #endif
218         return -1;
219 }
220
221 int gAccel::accelAlloc(gUnmanagedSurface* surface)
222 {
223         int stride = (surface->stride + ACCEL_ALIGNMENT_MASK) & ~ACCEL_ALIGNMENT_MASK;
224         int size = stride * surface->y;
225         if (!size)
226         {
227                 eDebug("[gAccel] accelAlloc called with size 0");
228                 return -2;
229         }
230         if (surface->bpp == 8)
231                 size += 256 * 4;
232         else if (surface->bpp != 32)
233         {
234                 eDebug("[gAccel] Accel does not support bpp=%d", surface->bpp);
235                 return -4;
236         }
237
238 #ifdef ACCEL_DEBUG
239         eDebug("[gAccel] [%s] %p size=%d %dx%d:%d", __func__, surface, size, surface->x, surface->y, surface->bpp);
240 #endif
241
242         size += ACCEL_ALIGNMENT_MASK;
243         size >>= ACCEL_ALIGNMENT_SHIFT;
244
245         eSingleLocker lock(m_allocation_lock);
246
247         for (MemoryBlockList::iterator it = m_accel_allocation.begin();
248                  it != m_accel_allocation.end();
249                  ++it)
250         {
251                 if ((it->surface == NULL) && (it->size >= size))
252                 {
253                         int remain = it->size - size;
254                         if (remain)
255                         {
256                                 /* Add empty item before this one with the remaining memory */
257                                 m_accel_allocation.insert(it, MemoryBlock(NULL, it->index, remain));
258                                 /* it points behind the new item */
259                                 it->index += remain;
260                                 it->size = size;
261                         }
262                         it->surface = surface;
263                         surface->data = ((unsigned char*)m_accel_addr) + (it->index << ACCEL_ALIGNMENT_SHIFT);
264                         surface->data_phys = m_accel_phys_addr + (it->index << ACCEL_ALIGNMENT_SHIFT);
265                         surface->stride = stride;
266                         dumpDebug();
267                         return 0;
268                 }
269         }
270
271         eDebug("[gAccel] alloc failed\n");
272         return -3;
273 }
274
275 void gAccel::accelFree(gUnmanagedSurface* surface)
276 {
277         int phys_addr = surface->data_phys;
278         if (phys_addr != 0)
279         {
280 #ifdef ACCEL_DEBUG
281                 eDebug("[gAccel] [%s] %p->%x %dx%d:%d", __func__, surface, surface->data_phys, surface->x, surface->y, surface->bpp);
282 #endif
283                 /* The lock scope is "good enough", the only other method that
284                  * might alter data_phys is the global release, and that will
285                  * be called in a safe context. So don't obtain the lock. */
286                 eSingleLocker lock(m_allocation_lock);
287
288                 phys_addr -= m_accel_phys_addr;
289                 phys_addr >>= ACCEL_ALIGNMENT_SHIFT;
290
291                 for (MemoryBlockList::iterator it = m_accel_allocation.begin();
292                          it != m_accel_allocation.end();
293                          ++it)
294                 {
295                         if (it->surface == surface)
296                         {
297                                 ASSERT(it->index == phys_addr);
298                                 /* Mark as free */
299                                 it->surface = NULL;
300                                 MemoryBlockList::iterator current = it;
301                                 /* Merge with previous item if possible */
302                                 if (it != m_accel_allocation.begin())
303                                 {
304                                         MemoryBlockList::iterator previous = it;
305                                         --previous;
306                                         if (previous->surface == NULL)
307                                         {
308                                                 current = previous;
309                                                 previous->size += it->size;
310                                                 m_accel_allocation.erase(it);
311                                         }
312                                 }
313                                 /* Merge with next item if possible */
314                                 if (current != m_accel_allocation.end())
315                                 {
316                                         it = current;
317                                         ++it;
318                                         if ((it != m_accel_allocation.end()) && (it->surface == NULL))
319                                         {
320                                                 current->size += it->size;
321                                                 m_accel_allocation.erase(it);
322                                         }
323                                 }
324                                 break;
325                         }
326                 }
327                 /* Mark as disposed (yes, even if it wasn't in our administration) */
328                 surface->data = 0;
329                 surface->data_phys = 0;
330                 dumpDebug();
331         }
332 }
333
334 eAutoInitP0<gAccel> init_gAccel(eAutoInitNumbers::graphic-2, "graphics acceleration manager");