|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set sw=2 ts=8 et ft=cpp : */ |
|
3 /* Copyright 2012 Mozilla Foundation and Mozilla contributors |
|
4 * |
|
5 * Licensed under the Apache License, Version 2.0 (the "License"); |
|
6 * you may not use this file except in compliance with the License. |
|
7 * You may obtain a copy of the License at |
|
8 * |
|
9 * http://www.apache.org/licenses/LICENSE-2.0 |
|
10 * |
|
11 * Unless required by applicable law or agreed to in writing, software |
|
12 * distributed under the License is distributed on an "AS IS" BASIS, |
|
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
14 * See the License for the specific language governing permissions and |
|
15 * limitations under the License. |
|
16 */ |
|
17 |
|
18 #include <fcntl.h> |
|
19 #include <linux/fb.h> |
|
20 #include <linux/kd.h> |
|
21 #include <stdio.h> |
|
22 #include <stdlib.h> |
|
23 #include <sys/ioctl.h> |
|
24 #include <sys/mman.h> |
|
25 #include <sys/types.h> |
|
26 #include <unistd.h> |
|
27 |
|
28 #include <vector> |
|
29 |
|
30 #include "android/log.h" |
|
31 |
|
32 #include "Framebuffer.h" |
|
33 #include "gfxContext.h" |
|
34 #include "gfxImageSurface.h" |
|
35 #include "gfxUtils.h" |
|
36 #include "mozilla/FileUtils.h" |
|
37 #include "nsTArray.h" |
|
38 #include "nsRegion.h" |
|
39 |
|
40 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) |
|
41 |
|
42 using namespace std; |
|
43 |
|
44 namespace mozilla { |
|
45 |
|
46 namespace Framebuffer { |
|
47 |
|
48 static int sFd = -1; |
|
49 static size_t sMappedSize; |
|
50 static struct fb_var_screeninfo sVi; |
|
51 static size_t sActiveBuffer; |
|
52 typedef vector<nsRefPtr<gfxImageSurface> > BufferVector; |
|
53 BufferVector* sBuffers; |
|
54 static gfxIntSize *sScreenSize = nullptr; |
|
55 |
|
56 BufferVector& Buffers() { return *sBuffers; } |
|
57 |
|
58 bool |
|
59 SetGraphicsMode() |
|
60 { |
|
61 ScopedClose fd(open("/dev/tty0", O_RDWR | O_SYNC)); |
|
62 if (0 > fd.get()) { |
|
63 // This is non-fatal; post-Cupcake kernels don't have tty0. |
|
64 LOG("No /dev/tty0?"); |
|
65 } else if (ioctl(fd.get(), KDSETMODE, (void*) KD_GRAPHICS)) { |
|
66 LOG("Error setting graphics mode on /dev/tty0"); |
|
67 return false; |
|
68 } |
|
69 return true; |
|
70 } |
|
71 |
|
72 bool |
|
73 Open() |
|
74 { |
|
75 if (0 <= sFd) |
|
76 return true; |
|
77 |
|
78 if (!SetGraphicsMode()) |
|
79 return false; |
|
80 |
|
81 ScopedClose fd(open("/dev/graphics/fb0", O_RDWR)); |
|
82 if (0 > fd.get()) { |
|
83 LOG("Error opening framebuffer device"); |
|
84 return false; |
|
85 } |
|
86 |
|
87 struct fb_fix_screeninfo fi; |
|
88 if (0 > ioctl(fd.get(), FBIOGET_FSCREENINFO, &fi)) { |
|
89 LOG("Error getting fixed screeninfo"); |
|
90 return false; |
|
91 } |
|
92 |
|
93 if (0 > ioctl(fd.get(), FBIOGET_VSCREENINFO, &sVi)) { |
|
94 LOG("Error getting variable screeninfo"); |
|
95 return false; |
|
96 } |
|
97 |
|
98 sMappedSize = fi.smem_len; |
|
99 void* mem = mmap(0, sMappedSize, PROT_READ | PROT_WRITE, MAP_SHARED, |
|
100 fd.rwget(), 0); |
|
101 if (MAP_FAILED == mem) { |
|
102 LOG("Error mmap'ing framebuffer"); |
|
103 return false; |
|
104 } |
|
105 |
|
106 sFd = fd.get(); |
|
107 fd.forget(); |
|
108 |
|
109 // The android porting doc requires a /dev/graphics/fb0 device |
|
110 // that's double buffered with r5g6b5 format. Hence the |
|
111 // hard-coded numbers here. |
|
112 gfxImageFormat format = gfxImageFormat::RGB16_565; |
|
113 if (!sScreenSize) { |
|
114 sScreenSize = new gfxIntSize(sVi.xres, sVi.yres); |
|
115 } |
|
116 long stride = fi.line_length; |
|
117 size_t numFrameBytes = stride * sScreenSize->height; |
|
118 |
|
119 sBuffers = new BufferVector(2); |
|
120 unsigned char* data = static_cast<unsigned char*>(mem); |
|
121 for (size_t i = 0; i < 2; ++i, data += numFrameBytes) { |
|
122 memset(data, 0, numFrameBytes); |
|
123 Buffers()[i] = new gfxImageSurface(data, *sScreenSize, stride, format); |
|
124 } |
|
125 |
|
126 // Clear the framebuffer to a known state. |
|
127 Present(nsIntRect()); |
|
128 |
|
129 return true; |
|
130 } |
|
131 |
|
132 bool |
|
133 GetSize(nsIntSize *aScreenSize) { |
|
134 // If the framebuffer has been opened, we should always have the size. |
|
135 if (sScreenSize) { |
|
136 *aScreenSize = *sScreenSize; |
|
137 return true; |
|
138 } |
|
139 |
|
140 ScopedClose fd(open("/dev/graphics/fb0", O_RDWR)); |
|
141 if (0 > fd.get()) { |
|
142 LOG("Error opening framebuffer device"); |
|
143 return false; |
|
144 } |
|
145 |
|
146 if (0 > ioctl(fd.get(), FBIOGET_VSCREENINFO, &sVi)) { |
|
147 LOG("Error getting variable screeninfo"); |
|
148 return false; |
|
149 } |
|
150 |
|
151 sScreenSize = new gfxIntSize(sVi.xres, sVi.yres); |
|
152 *aScreenSize = *sScreenSize; |
|
153 return true; |
|
154 } |
|
155 |
|
156 void |
|
157 Close() |
|
158 { |
|
159 if (0 > sFd) |
|
160 return; |
|
161 |
|
162 munmap(Buffers()[0]->Data(), sMappedSize); |
|
163 delete sBuffers; |
|
164 sBuffers = nullptr; |
|
165 delete sScreenSize; |
|
166 sScreenSize = nullptr; |
|
167 |
|
168 close(sFd); |
|
169 sFd = -1; |
|
170 } |
|
171 |
|
172 gfxASurface* |
|
173 BackBuffer() |
|
174 { |
|
175 return Buffers()[!sActiveBuffer]; |
|
176 } |
|
177 |
|
178 static gfxASurface* |
|
179 FrontBuffer() |
|
180 { |
|
181 return Buffers()[sActiveBuffer]; |
|
182 } |
|
183 |
|
184 void |
|
185 Present(const nsIntRegion& aUpdated) |
|
186 { |
|
187 sActiveBuffer = !sActiveBuffer; |
|
188 |
|
189 sVi.yres_virtual = sVi.yres * 2; |
|
190 sVi.yoffset = sActiveBuffer * sVi.yres; |
|
191 sVi.bits_per_pixel = 16; |
|
192 if (ioctl(sFd, FBIOPUT_VSCREENINFO, &sVi) < 0) { |
|
193 LOG("Error presenting front buffer"); |
|
194 } |
|
195 |
|
196 nsRefPtr<gfxContext> ctx = new gfxContext(BackBuffer()); |
|
197 gfxUtils::PathFromRegion(ctx, aUpdated); |
|
198 ctx->Clip(); |
|
199 ctx->SetSource(FrontBuffer()); |
|
200 ctx->SetOperator(gfxContext::OPERATOR_SOURCE); |
|
201 ctx->Paint(1.0); |
|
202 } |
|
203 |
|
204 } // namespace Framebuffer |
|
205 |
|
206 } // namespace mozilla |