summaryrefslogtreecommitdiff
path: root/src/framebuffer.c
blob: 5cb41fdde698bedc3bcf27c682f85a770691e04b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <framebuffer.h>

#include <mailbox.h>
#include <string.h>

#include <stddef.h>
#include <stdint.h>

#define WIDTH     640
#define HEIGHT    480
#define DEPTH      24
#define ALIGNMENT  16 // Framebuffer byte alignment.

static Framebuffer framebuffer = {};

bool framebuffer_init(uint32_t* error) {
  MAIL_T uint32_t InitFramebuffer[24] = {
    /*00*/96, // Size in bytes, aligned to MAIL_ALIGN.
    /*01*/MAILBOX_REQUEST,
    /*02*/TAG_FRAMEBUFFER_SET_PHYSICAL_SCREEN_SIZE, 8, MAILBOX_REQUEST, WIDTH, HEIGHT,
    /*07*/TAG_FRAMEBUFFER_SET_VIRTUAL_SCREEN_SIZE,  8, MAILBOX_REQUEST, WIDTH, HEIGHT,
    /*12*/TAG_FRAMEBUFFER_SET_DEPTH,                4, MAILBOX_REQUEST, DEPTH,
    /*16*/TAG_FRAMEBUFFER_ALLOCATE,                 8, MAILBOX_REQUEST, ALIGNMENT, 0,
    /*21*/TAG_END,
    /*22*/0, 0 // Padding.
  };
  const uint32_t result = mbox_write(PROPERTY_CHANNEL, InitFramebuffer);
  if (result != MAILBOX_SUCCESS) {
    goto end;
  }
  
  // The input mail is overwritten with the response.
  //
  // TAG_FRAMEBUFFER_ALLOCATE response:
  //   u32 fb base address
  //   u32 fb size
  // TODO: Do we need & 0x3FFFFFFF? Something about converting GPU address space
  // to ARM address space.
  // TODO: Should we read back the pitch, or does pitch match width?
  framebuffer = (Framebuffer) {
    .pixels = (Pixel*)((uintptr_t)InitFramebuffer[19] & 0x3FFFFFFF),
    .size   = InitFramebuffer[20],
    .width  = InitFramebuffer[5],
    .height = InitFramebuffer[6],
    .depth  = InitFramebuffer[15]
  };

end:
  *error = result;
  return result == MAILBOX_SUCCESS;
}

const Framebuffer* framebuffer_get() {
  return &framebuffer;
}

static inline uint32_t framebuffer_num_pixels() {
  const uint32_t num_channels = framebuffer.depth / 8;
  const uint32_t num_pixels   = framebuffer.size  / num_channels;
  return num_pixels;
}

void framebuffer_present(const Pixel* pixels) {
  const uint32_t num_pixels = framebuffer_num_pixels();
  memcpy(framebuffer.pixels, pixels, num_pixels);
}

void framebuffer_clear(Pixel colour) {
  const uint32_t num_pixels = framebuffer_num_pixels();
  volatile Pixel* fb = framebuffer.pixels;
  for (size_t i = 0; i < num_pixels; i++) {
    fb->r = colour.r;
    fb->g = colour.g;
    fb->b = colour.b;
    fb++;
  }
}