0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

mikanOS 4章を整理 [前編]

Last updated at Posted at 2022-04-01

はじめに

今回は RGB を意識して
Frame Buffer を制御してみる。
前回のコードからの変更点も含めて必要なフローをまとめた

⇦前|mikanOS 3章を整理[後編]

PIXEL control flow

flow_chart.png

諸情報を構造体で Kernel に共有

4 章のソースからヘッダファイル"frame_buffer_config.hpp"が追加されます。

frame_buffer_config.hpp
#pragma once
#include <stdint.h>
enum PixelFormat {
  kPixelRGBResv8BitPerColor,
  kPixelBGRResv8BitPerColor,
};
struct FrameBufferConfig {
  uint8_t* frame_buffer;
  uint32_t pixels_per_scan_line;
  uint32_t horizontal_resolution;
  uint32_t vertical_resolution;
  enum PixelFormat pixel_format;
};

enum は初対面。ココが分かりやすい。
なぜ、このような事をするのか、答えは Main.c にありました。

Main.c
  struct FrameBufferConfig config = {      //struct FrameBufferConfig{
    (UINT8*)gop->Mode->FrameBufferBase,    //  uint8_t* frame_buffer;
    gop->Mode->Info->PixelsPerScanLine,    //  uint32_t pixels_per_scan_line;
    gop->Mode->Info->HorizontalResolution, //  uint32_t horizontal_resolution;
    gop->Mode->Info->VerticalResolution,   //  vertical_resolution;
    0                                      //  enum PixelFormat pixel_format;};
  };

FrameBufferBase はピクセルそのものなので、
それ以外が何者か調べてみました。

pixel_exp.png
前述の struct FrameZBufferConfig config の後に
以下の記述が Main.c で続きます。

Main.c
  switch (gop->Mode->Info->PixelFormat) {
    case PixelRedGreenBlueReserved8BitPerColor:
      config.pixel_format = kPixelRGBResv8BitPerColor;
      break;
    case PixelBlueGreenRedReserved8BitPerColor:
      config.pixel_format = kPixelBGRResv8BitPerColor;
      break;
    default:
      Print(L"Unimplemented pixel format: %d\n", gop->Mode->Info->PixelFormat);
      Halt();
  }

gop->Mode->Info->PixelFormat を確認して,
RGB であれば、kPixelRGBResv8BitPerColor
BGR であれば、kPixelBGRResv8BitPerColorとしています。
※kPixelRGBResv8BitPerColor/kPixelBGRResv8BitPerColor は
 UEFI の規格書にないパラメータなので有難くコピーさせていただきます。

画像に関する緒情報を構造体 config に集約している事が分かります。
これらを kernel に渡すために Main.c の記述は以下のように変更します。

Main.c
//[before]
    typedef void EntryPointType(UINT64, UINT64);
    EntryPointType* entry_point = (EntryPointType*)entry_addr;
    entry_point(gop->Mode->FrameBufferBase, gop->Mode->FrameBufferSize);

//[after]
    typedef void EntryPointType(const struct FrameBufferConfig*);
    EntryPointType* entry_point = (EntryPointType*)entry_addr;
    entry_point(&config);

画面全体を白塗り

図1.png
白線 1 本目 (x,y): (0,0)->(0,1)->(0,2),,,,,->(0,vertical_resolution-1)
白線 2 本目 (x,y): (1,0)->(1,1)->(1,2),,,,,->(1,vertical_resolution-1)
っというように sample code では縦の白線を繋ぎ合わせて画面を白くしています。

main.cpp
extern "C" void KernelMain(const FrameBufferConfig& frame_buffer_config) {
  for (int x = 0; x < frame_buffer_config.horizontal_resolution; ++x) {
    for (int y = 0; y < frame_buffer_config.vertical_resolution; ++y) {
/*ココ=>*/ WritePixel(frame_buffer_config, x, y, {255, 255, 255});
    }
  }
  while (1) __asm__("hlt");
}

次に 1 ピクセルに色付けするための事前知識を整理します。
・1 ピクセル 32bit(4Byte)
 =>RGB の場合
  8bit(1Byte) : Red
  8bit(1Byte) : Green
  8bit(1Byte) : Blue
  8bit(1Byte) : Reserved
 =>BGR の場合
  8bit(1Byte) : Blue
  8bit(1Byte) : Green
  8bit(1Byte) : Red
  8bit(1Byte) : Reserved
・各ピクセルを総合し、配列として一塊で考えて制御する
・x 軸には表示できない領域もピクセルを配置している

シンプルに簡潔に伝えたかったのですが
むしろ長いコメントになった(伝わってるかなー、ボキャ貧でスマソ)。

main.cpp
struct PixelColor {
  uint8_t r, g, b;
};

int WritePixel(const FrameBufferConfig& config,
               int x, int y, const PixelColor& c) {
  /*↓ 何個目の pixel を編集するか整理*/
  const int pixel_position = config.pixels_per_scan_line * y + x;

  /*↓ pixel_position が分かれば、1pixel=32bit/uint8=8bitなので 
      pixel_position *4 とすると &config.frame_buffer[4 * pixel_position] は
      [R / G / B / Reserved] or [B / G / R / Reserved]の
      最初の R or B のアドレスを呼び出せる*/
  uint8_t* p = &config.frame_buffer[4 * pixel_position];

  /*ポインタを使って各 pixel のアドレスを p と定義しているため p[0],p[1],p[2] とシンプルに書ける*/
  p[0] = c.r;
  p[1] = c.g;
  p[2] = c.b;
  return 0;
}

あとは pixel format に併せて RGB/BGR の並びを変える記述を追記

main.cpp
struct PixelColor {
  uint8_t r, g, b;
};

int WritePixel(const FrameBufferConfig& config,
               int x, int y, const PixelColor& c) {
  const int pixel_position = config.pixels_per_scan_line * y + x;
  if (config.pixel_format == kPixelRGBResv8BitPerColor) {
    uint8_t* p = &config.frame_buffer[4 * pixel_position];
    p[0] = c.r;
    p[1] = c.g;
    p[2] = c.b;
  } else if (config.pixel_format == kPixelBGRResv8BitPerColor) {
    uint8_t* p = &config.frame_buffer[4 * pixel_position];
    p[0] = c.b;
    p[1] = c.g;
    p[2] = c.r;
  } else {
    return -1;
  }
  return 0;
}

画面一部を緑塗り

以下の白塗りの領域に一部上書きで緑塗りの領域を指定します。

main.cpp
//[before]
extern "C" void KernelMain(const FrameBufferConfig& frame_buffer_config) {
  for (int x = 0; x < frame_buffer_config.horizontal_resolution; ++x) {
    for (int y = 0; y < frame_buffer_config.vertical_resolution; ++y) {
      WritePixel(frame_buffer_config, x, y, {255, 255, 255});
    }
  }
  while (1) __asm__("hlt");
}
/***********/

//[after]
extern "C" void KernelMain(const FrameBufferConfig& frame_buffer_config) {
  for (int x = 0; x < frame_buffer_config.horizontal_resolution; ++x) {
    for (int y = 0; y < frame_buffer_config.vertical_resolution; ++y) {
      WritePixel(frame_buffer_config, x, y, {255, 255, 255});
    }
  }
  for (int x = 0; x < 200; ++x) {
    for (int y = 0; y < 100; ++y) {
      WritePixel(frame_buffer_config, 100 + x, 100 + y, {0, 255, 0});
    }
  }
  while (1) __asm__("hlt");
}

後編はブートローダーの修正と
C++ クラスを使った main.cpp の書き換えとかボンヤリ考えてます。
(C++ 初心者だから勉強ですね、ワクワク)

make を整理するかは悩み中です。

0
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?