fb9283a9d272a0ce68d9e85b4ed1429f794c701d
[framework/osp/shell.git] / src / FShell_AppWidgetBuffer.cpp
1 //
2 // Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.1 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://floralicense.org/license/
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 /**
17  * @file                FShell_AppWidgetBuffer.cpp
18  * @brief               This is the implementation file for the _AppWidgetBuffer class.
19  */
20
21 #include <new>
22 #include <stdio.h>
23 #include <errno.h>
24 #include <sys/mman.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 #include <stddef.h>
32 #include <sys/shm.h>
33 #include <sys/ipc.h>
34 #include <FBaseSysLog.h>
35 #include "FShell_AppWidgetBuffer.h"
36
37 using namespace std;
38 using namespace Tizen::Base;
39 using namespace Tizen::Graphics;
40
41 namespace Tizen { namespace Shell
42 {
43
44 _AppWidgetBuffer::_AppWidgetBuffer(void)
45         : __screen(0)
46         , __pVisual(null)
47         , __dri2FileDescriptor(-1)
48 {
49 }
50
51 _AppWidgetBuffer::~_AppWidgetBuffer(void)
52 {
53 }
54
55 struct _Deleter
56 {
57         void operator()(char* pStr)
58         {
59                 free(pStr);
60         }
61 };
62
63 void
64 _AppWidgetBuffer::Initialize(void)
65 {
66         __pDisplay.reset(XOpenDisplay(null));
67         SysTryReturnVoidResult(NID_SHELL, __pDisplay, E_SYSTEM, "[E_SYSTEM] Propagating.");
68
69         Screen* pScreen = DefaultScreenOfDisplay(__pDisplay.get());
70         __screen = DefaultScreen(__pDisplay.get());
71         __pVisual = DefaultVisualOfScreen(pScreen);
72         SysTryReturnVoidResult(NID_SHELL, __pVisual, E_SYSTEM, "[E_SYSTEM] Propagating.");
73
74         Bool ret = False;
75         int eventBase = 0;
76         int errorBase = 0;
77         ret = DRI2QueryExtension(__pDisplay.get(), &eventBase, &errorBase);
78         if (!ret)
79         {
80                 SysLog(NID_SHELL, "Do not support");
81                 return;
82         }
83
84         int dri2Major = 0;
85         int dri2Minor = 0;
86         ret = DRI2QueryVersion(__pDisplay.get(), &dri2Major, &dri2Minor);
87         if (!ret)
88         {
89                 SysLog(NID_SHELL, "Do not support");
90                 return;
91         }
92
93         char* pDriverNameTemp = null;
94         char* pDeviceNameTemp = null;
95
96         ret = DRI2Connect(__pDisplay.get(), DefaultRootWindow(__pDisplay.get()), &pDriverNameTemp, &pDeviceNameTemp);
97         if (!ret)
98         {
99                 SysLog(NID_SHELL, "Do not support");
100                 return;
101         }
102
103         unique_ptr<char, _Deleter> pDriverName(pDriverNameTemp);
104         unique_ptr<char, _Deleter> pDeviceName(pDeviceNameTemp);
105
106         unique_ptr<int, _FileDescriptorDeleter> fileDescriptor(open(pDeviceName.get(), O_RDWR));
107         if (fileDescriptor.get() < 0)
108         {
109                 SysLog(NID_SHELL, "Do not support");
110                 return;
111         }
112
113         drm_magic_t magic = 0;
114         drmGetMagic(fileDescriptor.get(), &magic);
115         SysLog(NID_SHELL, "Magic [0x%x]", magic);
116         ret = DRI2Authenticate(__pDisplay.get(), DefaultRootWindow(__pDisplay.get()), magic);
117         SysTryReturnVoidResult(NID_SHELL, ret == True, E_SYSTEM, "[E_SYSTEM] Propagating.");
118
119         unique_ptr<tbm_bufmgr, _TbmBufMgrDeleter> pBufMgr(tbm_bufmgr_init(fileDescriptor.get()));
120         SysTryReturnVoidResult(NID_SHELL, pBufMgr, E_SYSTEM, "[E_SYSTEM] Propagating.");
121
122         __dri2FileDescriptor = move(fileDescriptor);
123         __pBufMgr = move(pBufMgr);
124 }
125
126 void*
127 _AppWidgetBuffer::AllocBuffer(Pixmap pixmap, const Tizen::Graphics::FloatDimension& size)
128 {
129         unique_ptr<_Buffer> pBuffer;
130
131         if (!IsGemBufferEnabled())
132         {
133                 pBuffer.reset(new (std::nothrow) _Buffer(this));
134         }
135         else
136         {
137                 pBuffer.reset(new (std::nothrow) _GemBuffer(this));
138         }
139
140         SysTryReturn(NID_SHELL, pBuffer, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
141
142         void* pNativeBuffer = pBuffer->AllocBuffer(pixmap, size);
143         SysTryReturn(NID_SHELL, pNativeBuffer, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
144
145         __pBuffer = move(pBuffer);
146
147         return pNativeBuffer;
148 }
149
150 void
151 _AppWidgetBuffer::DeallocBuffer(void)
152 {
153         SysTryReturnVoidResult(NID_SHELL, __pBuffer, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
154
155         __pBuffer->DeallocBuffer();
156 }
157
158 void*
159 _AppWidgetBuffer::LockBuffer(void)
160 {
161         SysTryReturn(NID_SHELL, __pBuffer, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
162
163         void* pNativeBuffer = __pBuffer->LockBuffer();
164         SysTryReturn(NID_SHELL, pNativeBuffer, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
165
166         return pNativeBuffer;
167 }
168
169 void
170 _AppWidgetBuffer::UnlockBuffer(void)
171 {
172         SysTryReturnVoidResult(NID_SHELL, __pBuffer, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
173
174         __pBuffer->UnlockBuffer();
175 }
176
177 bool
178 _AppWidgetBuffer::IsGemBufferEnabled(void) const
179 {
180         return  (__dri2FileDescriptor.get() >= 0);
181 }
182
183 Display*
184 _AppWidgetBuffer::GetDisplay(void) const
185 {
186         return __pDisplay.get();
187 }
188
189 GC
190 _AppWidgetBuffer::GetGc(void) const
191 {
192         SysTryReturn(NID_SHELL, __pBuffer, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
193
194         return __pBuffer->GetGc();
195 }
196
197 XImage*
198 _AppWidgetBuffer::GetXImage(void) const
199 {
200         SysTryReturn(NID_SHELL, __pBuffer, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
201
202         return __pBuffer->GetXImage();
203 }
204
205 Pixmap
206 _AppWidgetBuffer::GetPixmap(void) const
207 {
208         SysTryReturn(NID_SHELL, __pBuffer, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
209
210         return __pBuffer->GetPixmap();
211 }
212
213 void
214 _AppWidgetBuffer::Dump(void)
215 {
216         SysTryReturnVoidResult(NID_SHELL, __pBuffer, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
217
218         return __pBuffer->Dump();
219 }
220
221 _AppWidgetBuffer::_Buffer::_Buffer(_AppWidgetBuffer* pAppWidgetBuffer)
222         : __locked(false)
223         , __pixmap(0)
224         , __depth(sizeof(int))
225         , __pAppWidgetBuffer(pAppWidgetBuffer)
226         , __dumpFileIndex(0)
227         , __gc(null)
228         , __pXImage(null)
229 {
230         __xShmSegmentInfo.shmseg = 0;
231         __xShmSegmentInfo.shmid = -1;
232         __xShmSegmentInfo.shmaddr = 0;
233         __xShmSegmentInfo.readOnly = False;
234 }
235
236 _AppWidgetBuffer::_Buffer::~_Buffer(void)
237 {
238         DeleteBuffer();
239 }
240
241 void*
242 _AppWidgetBuffer::_Buffer::AllocBuffer(Pixmap pixmap, const Tizen::Graphics::FloatDimension& size)
243 {
244         __pixmap = pixmap;
245         __size = size;
246
247         OnCreateBuffer();
248
249         return LockBuffer();
250 }
251
252 void
253 _AppWidgetBuffer::_Buffer::DeallocBuffer(void)
254 {
255         OnDeleteBuffer();
256 }
257
258 void*
259 _AppWidgetBuffer::_Buffer::LockBuffer(void)
260 {
261         __locked = true;
262
263         return OnLockBuffer();
264 }
265
266 void
267 _AppWidgetBuffer::_Buffer::UnlockBuffer(void)
268 {
269         __locked = false;
270
271         return OnUnlockBuffer();
272 }
273
274 GC
275 _AppWidgetBuffer::_Buffer::GetGc(void) const
276 {
277         return __gc;
278 }
279
280 XImage*
281 _AppWidgetBuffer::_Buffer::GetXImage(void) const
282 {
283         return __pXImage;
284 }
285
286 Pixmap
287 _AppWidgetBuffer::_Buffer::GetPixmap(void) const
288 {
289         return __pixmap;
290 }
291
292 void
293 _AppWidgetBuffer::_Buffer::Dump(void)
294 {
295         void* pBuffer = null;
296         bool lock = false;
297         if (__locked)
298         {
299                 pBuffer = GetBuffer();
300         }
301         else
302         {
303                 lock = true;
304                 pBuffer = LockBuffer();
305         }
306
307         SysTryReturnVoidResult(NID_SHELL, pBuffer, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
308
309         int size = static_cast<int>(__size.width) * static_cast<int>(__size.height) * __depth;
310
311         char fileName[1024];
312         memset(fileName, 0, sizeof(fileName));
313         snprintf(fileName, sizeof(fileName), "./dump%d.raw", __dumpFileIndex++);
314
315         FILE* pFile = fopen(fileName, "w+b");
316         if (pFile)
317         {
318                 fwrite(pBuffer, size, 1, pFile);
319                 fclose(pFile);
320                 SysSecureLog(NID_SHELL, "buffer (0x%x) size (%d) pixmapId (%d)", pBuffer, size, __pixmap);
321         }
322         else
323         {
324                 SysSecureLog(NID_SHELL, "File open failed: (%s) buffer (0x%x) size (%d) pixmapId (%d)", strerror(errno), pBuffer, size, __pixmap);
325         }
326
327         if (lock)
328         {
329                 UnlockBuffer(); 
330         }
331 }
332
333 void*
334 _AppWidgetBuffer::_Buffer::GetBuffer(void)
335 {
336         return OnLockBuffer();
337 }
338
339 void
340 _AppWidgetBuffer::_Buffer::DeleteBuffer(void)
341 {
342         if (__pAppWidgetBuffer->__pDisplay.get())
343         {
344                 if (__gc)
345                 {
346                         XFreeGC(__pAppWidgetBuffer->__pDisplay.get(), __gc);
347                         XShmDetach(__pAppWidgetBuffer->__pDisplay.get(), &__xShmSegmentInfo);
348
349                         if (__pXImage)
350                         {
351                                 XDestroyImage(__pXImage);
352                                 __pXImage = null;
353                         }
354
355                         if (__xShmSegmentInfo.shmaddr)
356                         {
357                                 shmdt(__xShmSegmentInfo.shmaddr);
358                                 __xShmSegmentInfo.shmaddr = null;
359                         }
360
361                         if (__xShmSegmentInfo.shmid >= 0)
362                         {
363                                 shmctl(__xShmSegmentInfo.shmid, IPC_RMID, 0);
364                                 __xShmSegmentInfo.shmid = -1;
365                         }
366
367                         __gc = null;
368                 }
369         }
370 }
371
372 void
373 _AppWidgetBuffer::_Buffer::OnCreateBuffer(void)
374 {
375         int bufferSize = static_cast<int>(__size.width) * static_cast<int>(__size.height) * __depth;
376         SysLog(NID_SHELL, "%d [%f %f %d]", bufferSize, __size.width, __size.height, __depth);
377
378         __xShmSegmentInfo.shmid = shmget(IPC_PRIVATE, bufferSize, IPC_CREAT | 0666);
379         SysTryReturnVoidResult(NID_SHELL, __xShmSegmentInfo.shmid >= 0, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
380
381         __xShmSegmentInfo.readOnly = False;
382         __xShmSegmentInfo.shmaddr = static_cast<char*>(shmat(__xShmSegmentInfo.shmid, null, 0));
383         SysTryCatch(NID_SHELL, __xShmSegmentInfo.shmaddr != (void*)-1, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
384
385         __pXImage = XShmCreateImage(__pAppWidgetBuffer->__pDisplay.get(), __pAppWidgetBuffer->__pVisual, 32, ZPixmap, null, &__xShmSegmentInfo, __size.width, __size.height);
386         SysTryCatch(NID_SHELL, __pXImage, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
387
388         __pXImage->data = __xShmSegmentInfo.shmaddr;
389         XShmAttach(__pAppWidgetBuffer->__pDisplay.get(), &__xShmSegmentInfo);
390         XSync(__pAppWidgetBuffer->__pDisplay.get(), False);
391
392         __gc = XCreateGC(__pAppWidgetBuffer->__pDisplay.get(), static_cast<Pixmap>(__pixmap), 0, null);
393         SysTryCatch(NID_SHELL, __gc, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
394
395         return;
396
397 CATCH:
398
399         XShmDetach(__pAppWidgetBuffer->__pDisplay.get(), &__xShmSegmentInfo);
400
401         if (__pXImage)
402         {
403                 XDestroyImage(__pXImage);
404                 __pXImage = null;
405         }
406
407         if (__xShmSegmentInfo.shmaddr != (void *)-1)
408         {
409                 shmdt(__xShmSegmentInfo.shmaddr);
410                 __xShmSegmentInfo.shmaddr = null;
411         }
412
413         if (__xShmSegmentInfo.shmid >= 0)
414         {
415                 shmctl(__xShmSegmentInfo.shmid, IPC_RMID, 0);
416                 __xShmSegmentInfo.shmid = -1;
417         }
418 }
419
420 void
421 _AppWidgetBuffer::_Buffer::OnDeleteBuffer(void)
422 {
423         DeleteBuffer();
424 }
425
426 void*
427 _AppWidgetBuffer::_Buffer::OnLockBuffer(void)
428 {
429         return __xShmSegmentInfo.shmaddr;
430 }
431
432 void
433 _AppWidgetBuffer::_Buffer::OnUnlockBuffer(void)
434 {
435 //      DeleteBuffer();
436 }
437
438 void*
439 _AppWidgetBuffer::_Buffer::OnGetBuffer(void)
440 {
441         return __xShmSegmentInfo.shmaddr;
442 }
443
444 _AppWidgetBuffer::_GemBuffer::_GemBuffer(_AppWidgetBuffer* pAppWidgetBuffer)
445         : _Buffer(pAppWidgetBuffer)
446         , __pDri2Buffer(null)
447         , __count(1)
448         , __outCount(0)
449         , __pTbmBo(null)
450         , __pGemBuffer(null)
451         , __pCompensateBuffer(null)
452 {
453         __attachments[0] = DRI2BufferFrontLeft;
454 }
455
456 _AppWidgetBuffer::_GemBuffer::~_GemBuffer(void)
457 {
458         DeleteGemBuffer();
459 }
460
461 void
462 _AppWidgetBuffer::_GemBuffer::DeleteGemBuffer(void)
463 {
464         if (__pCompensateBuffer)
465         {
466                 free(__pCompensateBuffer);
467                 __pCompensateBuffer = null;
468         }
469
470         if (__pTbmBo)
471         {
472                 tbm_bo_unref(__pTbmBo);
473                 __pTbmBo = null;
474
475                 DRI2DestroyDrawable(__pAppWidgetBuffer->__pDisplay.get(), __pixmap);
476         }
477 }
478
479 void
480 _AppWidgetBuffer::_GemBuffer::OnCreateBuffer(void)
481 {
482         SysLog(NID_SHELL, "[%f %f]", __size.width, __size.height);
483
484         unsigned int pitch = 0;
485
486         DRI2CreateDrawable(__pAppWidgetBuffer->__pDisplay.get(), __pixmap);
487
488         int width = static_cast<int>(__size.width);
489         int height = static_cast<int>(__size.height);
490
491         __pDri2Buffer = DRI2GetBuffers(__pAppWidgetBuffer->__pDisplay.get(), __pixmap, &width, &height, __attachments, __count, &__outCount);
492         SysTryCatch(NID_SHELL, __pDri2Buffer && __pDri2Buffer->name, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
493
494         __gemSize.width = width;
495         __gemSize.height = height;
496
497         SysSecureLog(NID_SHELL, "0x%x [%d %d %d] [%d %d]", __pDri2Buffer, __outCount, __pDri2Buffer->name, __pDri2Buffer->pitch, width, height);
498
499         __pTbmBo = tbm_bo_import(__pAppWidgetBuffer->__pBufMgr.get(), __pDri2Buffer->name);
500         SysTryCatch(NID_SHELL, __pTbmBo, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
501         
502         pitch = __gemSize.width * __depth;
503         if (__pDri2Buffer->pitch != pitch)
504         {
505                 __pCompensateBuffer = calloc(1, pitch * __gemSize.height);
506                 SysTryCatch(NID_SHELL, __pCompensateBuffer, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
507
508                 SysLog(NID_SHELL, "0x%x [%d %d %d]", __pCompensateBuffer, __depth, __gemSize.width, __gemSize.height);
509         }
510
511         return;
512
513 CATCH:
514
515         DRI2DestroyDrawable(__pAppWidgetBuffer->__pDisplay.get(), __pixmap);
516 }
517
518 void
519 _AppWidgetBuffer::_GemBuffer::OnDeleteBuffer(void)
520 {
521         DeleteGemBuffer();
522 }
523
524 void*
525 _AppWidgetBuffer::_GemBuffer::OnLockBuffer(void)
526 {
527         if (!__pGemBuffer)
528         {
529                 tbm_bo_handle handle;
530                 handle = tbm_bo_map(__pTbmBo, TBM_DEVICE_CPU, TBM_OPTION_READ | TBM_OPTION_WRITE);
531                 __pGemBuffer = handle.ptr;
532         }
533
534         return __pCompensateBuffer ? __pCompensateBuffer : __pGemBuffer;
535 }
536
537 void
538 _AppWidgetBuffer::_GemBuffer::OnUnlockBuffer(void)
539 {
540         if (__pGemBuffer)
541         {
542                 if (__pCompensateBuffer)
543                 {
544                         int* pPixel = (int*)__pCompensateBuffer;
545                         int* pGemPixel = (int*)__pGemBuffer;
546                         int gap = __pDri2Buffer->pitch - (__gemSize.width * __depth);
547
548                         for (int y = 0; y < __gemSize.height; y++)
549                         {
550                                 for (int x = 0; x < __gemSize.width; x++)
551                                 {
552                                         *pGemPixel++ = *pPixel++;
553                                 }
554
555                                 pGemPixel = (int*)(((char*)pGemPixel) + gap);
556                         }
557                 }
558
559                 tbm_bo_unmap(__pTbmBo);
560                 __pGemBuffer = null;
561         }
562 }
563
564 void*
565 _AppWidgetBuffer::_GemBuffer::OnGetBuffer(void)
566 {
567         return __pGemBuffer;
568 }
569
570 }} // Tizen::Shell