a cow based x86_64 operating system, using limine and stivale2
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

604 lines
15 KiB

#include <stdbool.h>
// for initialization
#include <stivale2.h>
#include "../klib/string.h"
#include "../debug/logging.h"
//#include "../memory/kalloc.h"
#include "../common.h"
#include "../debug/assert.h"
#include "video.h"
#include "terminal.h"
#define MAX(X,Y) X > Y ? X : Y
#define BPP 4
static Image screen;
inline void lower_blit(const Image* src, const Image* dst,
uint16_t srcx, uint16_t srcy,
uint16_t dstx, uint16_t dsty,
uint16_t width, uint16_t height);
void initVideo(const struct stivale2_struct_tag_framebuffer* fbtag,
void* frame_buffer_virtual_address) {
assert(fbtag != NULL);
screen = (Image){
.w = fbtag->framebuffer_width,
.h = fbtag->framebuffer_height,
.pitch= fbtag->framebuffer_pitch,
.bpp = fbtag->framebuffer_bpp,
.pix = frame_buffer_virtual_address
};
assert(screen.bpp == 32);
}
void imageLower_blit(const Image* img,
uint16_t srcx, uint16_t srcy,
uint16_t dstx, uint16_t dsty,
uint16_t width, uint16_t height) {
lower_blit(img, &screen, srcx,srcy,dstx,dsty,width,height);
}
void imageLower_blitBinaryMask(
const Image* img,
uint16_t srcx, uint16_t srcy,
uint16_t dstx, uint16_t dsty,
uint16_t width, uint16_t height,
uint32_t black, uint32_t white) {
assert(img->bpp == 32);
// begining of the first line
uint8_t* dst_ptr = screen.pix + dsty * screen.pitch
+ dstx * BPP;
uint8_t* src_ptr = img->pix + srcy * img->pitch
+ srcx * BPP;
size_t copy_size = width * BPP;
size_t dst_skip = screen.pitch - copy_size;
size_t src_skip = img -> pitch - copy_size;
// assert that everything are 2-aligned
// so that we can process faster
assert((size_t)dst_ptr % 8 == 0);
assert((size_t)src_ptr % 8 == 0);
assert((size_t)copy_size % 8 == 0);
assert((size_t)dst_skip % 8 == 0);
assert((size_t)src_skip % 8 == 0);
uint32_t* src_ptr32 = (uint32_t *)src_ptr;
uint32_t* dst_ptr32 = (uint32_t *)dst_ptr;
for(size_t i = height+1; i > 0 ; i--) {
// allow GCC to perform eco+ vectorization
src_ptr32 = __builtin_assume_aligned(src_ptr32, 8);
dst_ptr32 = __builtin_assume_aligned(dst_ptr32, 8);
for(int i = copy_size / 4; i > 0; i--) {
if((uint8_t) *(src_ptr32++) != 0) {
*(dst_ptr32++) = white;
}
else
*(dst_ptr32++) = black;
}
//memcpy(dst_ptr, src_ptr, copy_size);
src_ptr32 += src_skip / 4;
dst_ptr32 += dst_skip / 4;
//src_ptr += img->pitch;
//dst_ptr += screen.pitch;
}
}
/**
* blit the image without any verification
* (faster than blit but riskier)
*/
inline void lower_blit(const Image* src, const Image* dst,
uint16_t srcx, uint16_t srcy,
uint16_t dstx, uint16_t dsty,
uint16_t width, uint16_t height) {
// begining of the first line
uint8_t* dst_line_start = dst->pix + dsty * dst->pitch
+ dstx * BPP;
uint8_t* src_line_start = src->pix + srcy * src->pitch
+ srcx * BPP;
size_t dst_skip = dst->pitch;
size_t src_skip = src->pitch;
size_t copy_size = width * BPP;
for(size_t i = height+1; i > 0 ; i--) {
memcpy(dst_line_start,
src_line_start,
copy_size);
//memset(dst_line_start, 0xffffffff, copy_size);
src_line_start += src_skip;
dst_line_start += dst_skip;
}
}
void imageFillRect(uint32_t color, const Rect* rect) {
uint32_t beginx, beginy, endx, endy;
if(rect != NULL) {
beginx = rect->x;
beginy = rect->y;
endx = rect->x + rect->w;
endy = rect->y + rect->h;
}
else {
beginx = 0;
beginy = 0;
endx = screen.w;
endy = screen.h;
}
for(size_t y = beginy; y < endy; y++) {
uint32_t* px = (uint32_t *) (
screen.pix
+ y * screen.pitch
+ beginx * 4);
for(size_t x = 0; x <= endx - beginx ; x++)
*(px++) = color;
}
}
void imageDraw(const Image* img, const Pos* srcpos, const Rect* dstrect) {
imageBlit(img, &screen, srcpos, dstrect);
}
void imageBlit(const Image* restrict src, Image* restrict dst,
const Pos* srcpos, const Rect* dstrect) {
uint32_t sxbegin,
sybegin,
dxbegin,
dybegin;
uint32_t w = INT32_MAX,
h = INT32_MAX;
// no srcrect is given
// lets assume we want to blit on the top left corner
if(!srcpos) {
sxbegin = 0;
sybegin = 0;
}
else {
sxbegin = MAX(srcpos->x, 0);
sybegin = MAX(srcpos->y, 0);
}
// destitation pos and dims
if(!dstrect) {
dxbegin = 0;
dybegin = 0;
}
else {
w = dstrect->w;
h = dstrect->h;
// cases where dstrect->x < 0
// or dstrect->y < 0
int16_t x = dstrect->x, y = dstrect->y;
if(x >= 0)
dxbegin = x;
else {
dxbegin = 0;
sxbegin += x;
w -= x;
}
if(y >= 0)
dybegin = y;
else {
dybegin = 0;
sybegin += y;
h -= y;
}
}
// sizes correction
if(sxbegin + w > src->w)
w = src->w - sxbegin;
if(sybegin + w > src->h)
h = src->h - sybegin;
if(dxbegin + w > dst->w)
w = src->w - sxbegin;
if(dybegin + h > dst->h)
h = src->h - sybegin;
lower_blit(src, dst, sxbegin, sybegin, dxbegin, dybegin, w,h);
}
/*
Image* alloc_image(uint32_t width, uint32_t height, uint32_t bpp) {
Image* ret = kmalloc(sizeof(Image));
ret->w = width;
ret->h = height;
ret->bpp = bpp;
assert(bpp % 8 == 0 || bpp == 1);
if(bpp == 1) {
// align on 1 byte
ret->pitch = (width + 7) / 8;
}
else
ret->pitch = (uint32_t)allign16(width * (bpp/8));
ret->pix = kmalloc(ret->pitch * height);
return ret;
}
*/
/*
void free_image(Image* im) {
assert(im != NULL);
kfree(im->pix);
}
*/
#define BMP_MAGIC (uint16_t)0x4D42
/**
*
* header format for a BMP file
*
**/
struct BMPFileHeader {
uint16_t magic; // should be eq to BMP_MAGIC
uint32_t size; // size of the entire file (in bytes)
uint16_t reserved1; //
uint16_t reserved2; //
uint32_t body_offset;// byte offset of the pixel body
uint32_t header_size;// should be eq to sizeof(BMPFileHeader)
int32_t w; // BMP width in pixels
int32_t h; // BMP height in pixels
uint16_t one; // should be eq to 1
uint16_t bpp; // bits per pixel
} __packed;
inline bool check_BMP_header(const struct BMPFileHeader* header) {
return header != NULL &&
header->magic != BMP_MAGIC &&
header->w > 0 &&
header->h > 0 &&
header->one == 1 ;
}
const Image* getScreenImage(void) {
return &screen;
}
extern uint8_t __image_pix;
/*
// assert that the checks are already performed
static Image* loadBMP_24(const struct BMPFileHeader* restrict header, const void* restrict body) {
assert(header->bpp == 24);
static int first = 0;
// should use this func only once.
// no dynamic alloc allowed
assert(first++ == 0);
uint32_t w = header->w;
uint32_t h = header->h;
static Image ret;
ret.w = w;
ret.h = h;
ret.bpp = 32;
ret.pitch = (uint32_t)allign16(w * 4);
ret.pix = &__image_pix;
const uint8_t* srcpix = body;
const size_t bpp = 3;
//ret = alloc_image(w,h, 32);
size_t bpitch = ret.pitch / 4;
uint32_t* pix32 = ret.pix;
for(size_t y = 0; y < h; y++) {
for(size_t x = 0; x < w; x++) {
const uint32_t* src_ptr = (const uint32_t *)(srcpix
+ x * bpp
+ (h-1 - y) * bpp * w);
/// the image is reversed along
/// the y axis
pix32[x + y * bpitch] = (*(const uint32_t *)src_ptr) & 0x00ffffff;
}
}
return &ret;
}
*/
/*
// assert that the checks are already performed
static Image* loadBMP_8(const struct BMPFileHeader* restrict header, const void* restrict body) {
assert(header->bpp == 8);
uint32_t w = header->w;
uint32_t h = header->h;
const uint8_t* srcpix = body;
Image* ret = alloc_image(w,h, 8);
size_t bpitch = ret->pitch;
uint32_t* pix32 = ret->pix;
for(size_t y = 0; y < h; y++) {
const uint8_t* src_ptr = (srcpix + (h-1 - y) * w);
for(size_t x = 0; x < w; x++) {
/// the image is reversed along
/// the y axis
pix32[x + y * bpitch] = *(src_ptr++);
}
}
return ret;
}
*/
/*
Image* loadBMP(const void* restrict rawFile) {
// the header should be at the beginning
const struct BMPFileHeader* header = rawFile;
if(check_BMP_header(header))
return NULL;
// only handle 32bit and 8bit image
assert(header->bpp == 8 || header->bpp == 24);
const void* body = (uint8_t *)header + header->body_offset;
switch(header->bpp) {
case 24:
return loadBMP_24(header, body);
break;
case 8:
assert(0);
//return loadBMP_8 (header, body);
default:
assert(0);
__builtin_unreachable();
}
}
*/
/*
map[] = {
(00): black black
(01): black white
(10): white black
(11): white white
}
for line
in =
for(ptr = col; ; ptr += 2px) {
in >>= 2;
in' = in or 0b11
*ptr = map+4*in'
}
*/
__attribute__((optimize("unroll-loops")))
void blitchar(const struct Image* charset,
char c, uint32_t fg_color, uint32_t bg_color,
uint16_t dstx, uint16_t dsty) {
const uint64_t colormap[] = {
((uint64_t) bg_color << 32) | bg_color,
((uint64_t) bg_color << 32) | fg_color,
((uint64_t) fg_color << 32) | bg_color,
((uint64_t) fg_color << 32) | fg_color,
};
uint16_t srcy = c * TERMINAL_FONTHEIGHT;
uint64_t* dst_ptr = (uint64_t *)(screen.pix + screen.pitch * dsty + 4 * dstx);
uint16_t dst_skip = screen.pitch - TERMINAL_FONTWIDTH * 4;
// 4 2-byte lines = 8*8 = 64 (1 access every 4 lines)
// 1st line address for the selected char
uint64_t* lines_ptr = (uint64_t*)charset->pix + srcy / sizeof(uint64_t);
// loop over 4-line chunks
uint64_t lines = *lines_ptr;
// 64 bit = 8 lines
for(size_t n_line = 8; n_line > 0; n_line--) {
// lines are 8bit aligned
for(size_t n_col2 = TERMINAL_FONTWIDTH / 2 ; n_col2 > 0 ; n_col2--) {
uint16_t index = lines & 0b11;
*(dst_ptr++) = colormap[index];
lines >>= 2;
}
dst_ptr += dst_skip / 8;
lines >>= 8 - TERMINAL_FONTWIDTH;
}
}
__attribute__((optimize("unroll-loops")))
void blitcharX2(const struct Image* charset,
char c, uint32_t fg_color, uint32_t bg_color,
uint16_t dstx, uint16_t dsty) {
const uint64_t colormap[] = {
((uint64_t) bg_color << 32) | bg_color,
((uint64_t) bg_color << 32) | fg_color,
((uint64_t) fg_color << 32) | bg_color,
((uint64_t) fg_color << 32) | fg_color,
};
uint16_t srcy = c * TERMINAL_FONTHEIGHT;
uint64_t* dst_ptr = (uint64_t *)(screen.pix + screen.pitch * dsty + 4 * dstx);
uint16_t dst_skip = 2 * screen.pitch - 2 * TERMINAL_FONTWIDTH * 4;
/// second line to modify
uint64_t* dst_ptr2 = dst_ptr + screen.pitch / 8;
uint64_t* lines_ptr = (uint64_t*)charset->pix + srcy / sizeof(uint64_t);
uint64_t lines = *lines_ptr;
for(size_t n_line = 8; n_line > 0; n_line--) {
for(size_t n_col2 = TERMINAL_FONTWIDTH / 2 ; n_col2 > 0 ; n_col2--) {
uint16_t index = lines & 0b11;
register uint64_t pixs_val = colormap[index];
register uint64_t pixs_val_low = pixs_val | (pixs_val << 32);
register uint64_t pixs_val_high = pixs_val | (pixs_val >> 32);
*(dst_ptr++) = pixs_val_low;
*(dst_ptr++) = pixs_val_high;
*(dst_ptr2++) = pixs_val_low;
*(dst_ptr2++) = pixs_val_high;
// x2
lines >>= 2;
}
dst_ptr += dst_skip / 8;
dst_ptr2 += dst_skip / 8;
lines >>= 8 - TERMINAL_FONTWIDTH;
}
}
// else this func wont work
static_assert(TERMINAL_FONTWIDTH == 6);
static_assert(TERMINAL_FONTWIDTH % 2 == 0);
static_assert(TERMINAL_FONTHEIGHT == 8);
static Image loadBMP_24b_1b_ret;
Image* loadBMP_24b_1b(const void* rawFile) {
const struct BMPFileHeader* header = rawFile;
static int first = 0;
// should use this func only once.
// no dynamic alloc allowed
assert(first++ == 0);
if(check_BMP_header(header))
return NULL;
uint32_t w = header->w;
uint32_t h = header->h;
const uint8_t* srcpix = (const uint8_t *)header + header->body_offset;
loadBMP_24b_1b_ret.w = w;
loadBMP_24b_1b_ret.h = h;
loadBMP_24b_1b_ret.bpp = 1;
loadBMP_24b_1b_ret.pitch = ((w+7) / 8);
loadBMP_24b_1b_ret.pix = &__image_pix;
assert(loadBMP_24b_1b_ret.pitch == 1);
assert(w == 6);
assert(h == 2048);
uint8_t* pix = loadBMP_24b_1b_ret.pix;
for(size_t y = 0; y < h; y++) {
uint8_t byte = 0;
for(size_t x = 0; x < w; x++) {
const uint8_t* src_ptr = (srcpix + 20 * (h-1 - y) + 3 * (w-1-x));
byte <<= 1;
// put 1 iif r channel > 128
byte |= *(src_ptr) >> 7;
//if((x % 8 == 0 && x != 0) || x == w-1) {
if(x == w-1) {
//pix[_x + y * bpitch] = byte;
}
}
pix[y] = byte;
}
return &loadBMP_24b_1b_ret;
}