v1.1.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Groups Pages
framebuffer.h
1 /* -*- mode: C; c-basic-offset: 4; intent-tabs-mode: nil -*-
2  *
3  * This file is part of the public interface to the Sifteo SDK.
4  * Copyright <c> 2012 Sifteo, Inc. All rights reserved.
5  */
6 
7 #pragma once
8 #ifdef NOT_USERSPACE
9 # error This is a userspace-only header, not allowed by the current build.
10 #endif
11 
12 #include <sifteo/abi.h>
13 #include <sifteo/macros.h>
14 #include <sifteo/math.h>
15 
16 namespace Sifteo {
17 
31 template <unsigned tWidth, unsigned tHeight, unsigned tBitsPerPixel>
32 struct FBDrawable {
33  _SYSAttachedVideoBuffer sys;
34 
38  static unsigned width() {
39  return tWidth;
40  }
41 
45  static unsigned height() {
46  return tHeight;
47  }
48 
52  static UInt2 size() {
53  return vec(tWidth, tHeight);
54  }
55 
60  static unsigned numColors() {
61  return 1 << tBitsPerPixel;
62  }
63 
68  static unsigned bitsPerPixel() {
69  return tBitsPerPixel;
70  }
71 
75  static unsigned sizeInBytes() {
76  return tWidth * tHeight * tBitsPerPixel / 8;
77  }
78 
82  static unsigned sizeInWords() {
83  return tWidth * tHeight * tBitsPerPixel / 16;
84  }
85 
95  void plot(UInt2 pos, unsigned colorIndex)
96  {
97  ASSERT(pos.x <= tWidth && pos.y <= tHeight);
98 
99  const unsigned pixelsPerByte = 8 / tBitsPerPixel;
100  const unsigned bytesPerLine = tWidth / pixelsPerByte;
101  const unsigned xByte = pos.x / pixelsPerByte;
102  const unsigned xBit = (pos.x % pixelsPerByte) * tBitsPerPixel;
103  const unsigned byteAddr = xByte + pos.y * bytesPerLine;
104  const unsigned pixelMask = ((1 << tBitsPerPixel) - 1) << xBit;
105 
106  uint8_t byte = _SYS_vbuf_peekb(&sys.vbuf, byteAddr);
107  byte &= ~pixelMask;
108  byte |= colorIndex << xBit;
109  _SYS_vbuf_pokeb(&sys.vbuf, byteAddr, byte);
110  }
111 
119  static uint16_t expand16(unsigned colorIndex)
120  {
121  switch (tBitsPerPixel) {
122  case 1: return colorIndex ? 0xFFFF : 0x0000;
123  case 2: colorIndex |= colorIndex << 2;
124  case 4: colorIndex |= colorIndex << 4;
125  case 8: colorIndex |= colorIndex << 8;
126  case 16: return colorIndex;
127  default: ASSERT(0);
128  }
129  }
130 
137  void span(UInt2 pos, unsigned width, unsigned colorIndex)
138  {
139  ASSERT(pos.x <= tWidth && width <= tWidth &&
140  (pos.x + width) <= tWidth && pos.y < tHeight);
141 
142  const unsigned pixelsPerWord = 16 / tBitsPerPixel;
143  const unsigned wordsPerLine = tWidth / pixelsPerWord;
144  const unsigned colorWord = expand16(colorIndex);
145 
146  // Calculate a base address in words, and
147  // left/right boundaries relative to that in bits.
148  unsigned addr = pos.x / pixelsPerWord + pos.y * wordsPerLine;
149  int start = (pos.x % pixelsPerWord) * tBitsPerPixel;
150  int end = start + width * tBitsPerPixel;
151 
152  while (end > 0) {
153  if (start <= 0 && end >= 16) {
154  // A run of complete words
155 
156  unsigned count = end / 16;
157  _SYS_vbuf_fill(&sys.vbuf, addr, colorWord, count);
158  addr += count;
159  unsigned bits = count * 16;
160  start -= bits;
161  end -= bits;
162 
163  } else {
164  // One partial word. (The first, last or only word)
165 
166  unsigned mask = bitRange<uint16_t>(start, end);
167  unsigned word = _SYS_vbuf_peek(&sys.vbuf, addr);
168  word &= ~mask;
169  word |= colorWord & mask;
170  _SYS_vbuf_poke(&sys.vbuf, addr, word);
171  addr++;
172  start -= 16;
173  end -= 16;
174  }
175  }
176  }
177 
184  void fill(UInt2 topLeft, UInt2 size, unsigned colorIndex)
185  {
186  while (size.y) {
187  span(topLeft, size.x, colorIndex);
188  size.y--;
189  topLeft.y++;
190  }
191  }
192 
196  void fill(unsigned colorIndex)
197  {
198  _SYS_vbuf_fill(&sys.vbuf, 0, expand16(colorIndex), sizeInWords());
199  }
200 
207  void bitmapSpan(UInt2 pos, unsigned width, const uint8_t *data)
208  {
209  ASSERT(pos.x <= tWidth && width <= tWidth &&
210  (pos.x + width) <= tWidth && pos.y < tHeight);
211 
212  const unsigned pixelsPerByte = 8 / tBitsPerPixel;
213  const unsigned bytesPerLine = tWidth / pixelsPerByte;
214 
215  // Base address in bits
216  unsigned addr = pos.x / pixelsPerByte + pos.y * bytesPerLine;
217 
218  // Bitmap alignment
219  unsigned shift = (pos.x % pixelsPerByte) * tBitsPerPixel;
220  unsigned invShift = 8 - shift;
221 
222  // Initial mask range, in bits, relative to the base address
223  int start = shift;
224  int end = start + width * tBitsPerPixel;
225 
226  while (end > 0) {
227  // One source byte at a time, splatted to either one or two
228  // destination bytes in VRAM.
229 
230  uint8_t source = *data;
231  data++;
232 
233  // First byte
234  unsigned mask = (0xFF << shift) & bitRange<uint16_t>(start, end);
235  unsigned byte = _SYS_vbuf_peekb(&sys.vbuf, addr);
236  byte &= ~mask;
237  byte |= (source << shift) & mask;
238  _SYS_vbuf_pokeb(&sys.vbuf, addr, byte);
239 
240  addr++;
241  start -= 8;
242  end -= 8;
243 
244  // Optional second byte
245  if (shift) {
246  unsigned mask = (0xFF >> invShift) & bitRange<uint16_t>(start, end);
247  unsigned byte = _SYS_vbuf_peekb(&sys.vbuf, addr);
248  byte &= ~mask;
249  byte |= (source >> invShift) & mask;
250  _SYS_vbuf_pokeb(&sys.vbuf, addr, byte);
251  }
252  }
253  }
254 
267  void bitmap(UInt2 topLeft, UInt2 size, const uint8_t *data, unsigned stride)
268  {
269  while (size.y) {
270  bitmapSpan(topLeft, size.x, data);
271  size.y--;
272  topLeft.y++;
273  data += stride;
274  }
275  }
276 
282  void set(const uint16_t *data) {
283  _SYS_vbuf_write(&sys.vbuf, 0, data, sizeInWords());
284  }
285 
289  _SYSVideoBuffer &videoBuffer() {
290  return sys.vbuf;
291  }
292 
296  CubeID cube() const {
297  return sys.cube;
298  }
299 };
300 
301 
304 
307 
310 
311 
322  _SYSAttachedVideoBuffer sys;
323 
331  void resizeFB(Int2 pixelSize) {
332  ASSERT((pixelSize.x & 1) == 0 &&
333  pixelSize.x * pixelSize.y <= 1536 &&
334  pixelSize.x <= 128 &&
335  pixelSize.y <= 128);
336 
337  _SYS_vbuf_poke(&sys.vbuf, offsetof(_SYSVideoRAM, stamp_pitch)/2,
338  (pixelSize.x >> 1) | (pixelSize.y << 8));
339  }
340 
351  template <unsigned tWidth, unsigned tHeight>
353  {
354  auto &fb = *reinterpret_cast<FBDrawable<tWidth, tHeight, 4>*>(this);
355  ASSERT(&fb.sys == &sys);
356  return fb;
357  }
358 
368  template <unsigned tWidth, unsigned tHeight>
370  {
371  _SYS_finish();
372  resizeFB(vec(tWidth, tHeight));
373  return getFB<tWidth, tHeight>();
374  }
375 
384  void setHWindow(uint8_t firstColumn, uint8_t numColumns) {
385  _SYS_vbuf_poke(&sys.vbuf, offsetof(_SYSVideoRAM, stamp_x)/2,
386  firstColumn | (numColumns << 8));
387  }
388 
396  void setBox(Int2 topLeft, Int2 size) {
397  _SYS_vbuf_poke(&sys.vbuf, offsetof(_SYSVideoRAM, first_line)/2,
398  topLeft.y | (size.y << 8));
399  setHWindow(topLeft.x, size.x);
400  }
401 
408  void setKeyIndex(unsigned index) {
409  _SYS_vbuf_pokeb(&sys.vbuf, offsetof(_SYSVideoRAM, stamp_key), index);
410  }
411 
417  void disableKey() {
418  setKeyIndex(16);
419  }
420 
424  _SYSVideoBuffer &videoBuffer() {
425  return sys.vbuf;
426  }
427 
431  CubeID cube() const {
432  return sys.cube;
433  }
434 };
435 
436 
441 }; // namespace Sifteo