Adds partially functional compositing buffer.

This commit is contained in:
Erik Abair 2021-11-29 13:08:49 -08:00
parent ab030c52eb
commit b3dadb4d0c
3 changed files with 143 additions and 81 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -24,20 +24,26 @@
// Subchannel reserved for interaction with the class 12 channel.
#define SUBCH_CLASS_12 6
#define SOURCE_OFFSET_X 100
#define SOURCE_OFFSET_y 16
#define SOURCE_WIDTH 126
#define SOURCE_HEIGHT 116
// Initial color for the compositing buffer.
#define COMPOSITING_BUFFER_COLOR 0x00CC2222
#define SOURCE_X 8
#define SOURCE_Y 8
#define SOURCE_WIDTH 128
#define SOURCE_HEIGHT 128
#define DESTINATION_X 256
#define DESTINATION_Y 176
static std::string OperationName(uint32_t operation);
static std::string ColorFormatName(uint32_t format);
static constexpr ImageBlitTests::BlitTest kTests[] = {
{NV09F_SET_OPERATION_BLEND_AND, NV04_SURFACE_2D_FORMAT_X8R8G8B8_X8R8G8B8},
{NV09F_SET_OPERATION_SRCCOPY, NV04_SURFACE_2D_FORMAT_X8R8G8B8_X8R8G8B8},
{NV09F_SET_OPERATION_BLEND_AND, NV04_SURFACE_2D_FORMAT_A8R8G8B8},
{NV09F_SET_OPERATION_SRCCOPY, NV04_SURFACE_2D_FORMAT_A8R8G8B8},
// {6, NV04_SURFACE_2D_FORMAT_X8R8G8B8_X8R8G8B8}, // BLEND_PREMULT?
{NV09F_SET_OPERATION_BLEND_AND, NV04_SURFACE_2D_FORMAT_X8R8G8B8_X8R8G8B8, 0.5f, false},
{NV09F_SET_OPERATION_BLEND_AND, NV04_SURFACE_2D_FORMAT_A8R8G8B8, 0.5f, false},
{NV09F_SET_OPERATION_BLEND_AND, NV04_SURFACE_2D_FORMAT_A8R8G8B8, 0.5f, true},
{NV09F_SET_OPERATION_SRCCOPY, NV04_SURFACE_2D_FORMAT_X8R8G8B8_X8R8G8B8, 0, false},
{NV09F_SET_OPERATION_SRCCOPY, NV04_SURFACE_2D_FORMAT_A8R8G8B8, 0, false},
{NV09F_SET_OPERATION_SRCCOPY, NV04_SURFACE_2D_FORMAT_A8R8G8B8, 0, true},
};
ImageBlitTests::ImageBlitTests(TestHost& host, std::string output_dir) : TestSuite(host, std::move(output_dir)) {
@ -52,121 +58,147 @@ ImageBlitTests::ImageBlitTests(TestHost& host, std::string output_dir) : TestSui
void ImageBlitTests::Initialize() {
SetDefaultTextureFormat();
SDL_Surface* test_image = IMG_Load("D:\\image_blit\\TestImage.png");
assert(test_image);
SDL_Surface* temp = IMG_Load("D:\\image_blit\\TestImage.png");
assert(temp);
SDL_Surface* test_image = SDL_ConvertSurfaceFormat(temp, SDL_PIXELFORMAT_BGRA32, 0);
SDL_free(temp);
image_pitch_ = test_image->pitch;
image_height_ = test_image->h;
uint32_t image_bytes = image_pitch_ * image_height_;
surface_memory_ = static_cast<uint8_t*>(MmAllocateContiguousMemory(image_bytes));
memcpy(surface_memory_, test_image->pixels, image_bytes);
source_image_ = static_cast<uint8_t*>(MmAllocateContiguousMemory(image_bytes));
memcpy(source_image_, test_image->pixels, image_bytes);
SDL_free(test_image);
uint32_t compositing_bytes = 4 * SOURCE_WIDTH * SOURCE_HEIGHT;
compositing_image_ = static_cast<uint8_t*>(MmAllocateContiguousMemory(compositing_bytes));
std::fill_n(reinterpret_cast<uint32_t*>(compositing_image_), compositing_bytes >> 2, COMPOSITING_BUFFER_COLOR);
// DONOTSUBMIT
auto foo = source_image_;
for (int y = 0; y < test_image->h; ++y) {
for (int x = 0; x < test_image->w; ++x) {
foo[3] = 0x33;
foo += 4;
}
}
// TODO: Provide a mechanism to find the next unused channel.
pb_create_dma_ctx(20, DMA_CLASS_3D, 0, MAXRAM, &image_src_dma_ctx_);
auto channel = 20;
pb_create_dma_ctx(channel++, DMA_CLASS_3D, 0, MAXRAM, &image_src_dma_ctx_);
pb_bind_channel(&image_src_dma_ctx_);
pb_create_gr_ctx(21, GR_CLASS_30, &null_ctx_);
pb_create_dma_ctx(channel++, DMA_CLASS_3D, 0, MAXRAM, &image_composite_dma_ctx_);
pb_bind_channel(&image_composite_dma_ctx_);
pb_create_gr_ctx(channel++, GR_CLASS_30, &null_ctx_);
pb_bind_channel(&null_ctx_);
pb_create_gr_ctx(22, GR_CLASS_19, &clip_rect_ctx_);
pb_create_gr_ctx(channel++, GR_CLASS_19, &clip_rect_ctx_);
pb_bind_channel(&clip_rect_ctx_);
// TODO: Provide a mechanism to find the next unused subchannel.
pb_bind_subchannel(SUBCH_CLASS_19, &clip_rect_ctx_);
pb_create_gr_ctx(23, GR_CLASS_12, &beta_ctx_);
pb_create_gr_ctx(channel++, GR_CLASS_12, &beta_ctx_);
pb_bind_channel(&beta_ctx_);
pb_bind_subchannel(SUBCH_CLASS_12, &beta_ctx_);
}
void ImageBlitTests::Deinitialize() {
MmFreeContiguousMemory(surface_memory_);
surface_memory_ = nullptr;
MmFreeContiguousMemory(source_image_);
source_image_ = nullptr;
MmFreeContiguousMemory(compositing_image_);
compositing_image_ = nullptr;
}
static uint32_t* set_beta(uint32_t* p, float value) {
// Sets the beta factor. The parameter is a signed fixed-point number with a sign bit and 31 fractional bits.
// Note that negative values are clamped to 0, and only 8 fractional bits are actually implemented in hardware.
uint32_t int_val;
if (value < 0.0f) {
int_val = 0;
} else {
if (value > 1.0f) {
value = 1.0f;
}
constexpr uint32_t kMaxValue = 0x7f800000;
int_val = static_cast<int>(value * static_cast<float>(kMaxValue));
int_val &= kMaxValue;
}
p = pb_push1_to(SUBCH_CLASS_12, p, NV012_SET_BETA, int_val);
return p;
}
void ImageBlitTests::Test(const BlitTest& test) {
host_.PrepareDraw(0x00660033);
uint32_t image_bytes = image_pitch_ * image_height_;
pb_set_dma_address(&image_src_dma_ctx_, surface_memory_, image_bytes - 1);
uint32_t in_x = SOURCE_OFFSET_X;
uint32_t in_y = SOURCE_OFFSET_y;
uint32_t out_x = 300;
uint32_t out_y = 200;
uint32_t width = SOURCE_WIDTH;
uint32_t height = SOURCE_HEIGHT;
uint32_t clip_x = 0;
uint32_t clip_y = 0;
uint32_t clip_w = host_.GetFramebufferWidth();
uint32_t clip_h = host_.GetFramebufferHeight();
uint32_t dest_pitch = 4 * host_.GetFramebufferWidth();
void ImageBlitTests::Render2D(uint32_t operation, uint32_t beta, uint32_t source_channel, uint32_t destination_channel,
uint32_t surface_format, uint32_t source_pitch, uint32_t destination_pitch,
uint32_t source_offset, uint32_t source_x, uint32_t source_y, uint32_t destination_offset,
uint32_t destination_x, uint32_t destination_y, uint32_t width, uint32_t height,
uint32_t clip_x, uint32_t clip_y, uint32_t clip_width, uint32_t clip_height) {
auto p = pb_begin();
p = pb_push1_to(SUBCH_CLASS_9F, p, NV_IMAGE_BLIT_OPERATION, test.blit_operation);
p = pb_push1_to(SUBCH_CLASS_62, p, NV10_CONTEXT_SURFACES_2D_SET_DMA_IN_MEMORY0, image_src_dma_ctx_.ChannelID);
p = pb_push1_to(SUBCH_CLASS_62, p, NV10_CONTEXT_SURFACES_2D_SET_DMA_IN_MEMORY1, 11); // DMA channel 11 - 0x1117
p = pb_push1_to(SUBCH_CLASS_9F, p, NV_IMAGE_BLIT_OPERATION, operation);
p = pb_push1_to(SUBCH_CLASS_62, p, NV10_CONTEXT_SURFACES_2D_SET_DMA_IN_MEMORY0, source_channel);
p = pb_push1_to(SUBCH_CLASS_62, p, NV10_CONTEXT_SURFACES_2D_SET_DMA_IN_MEMORY1, destination_channel);
p = pb_push1_to(SUBCH_CLASS_19, p, NV01_CONTEXT_CLIP_RECTANGLE_SET_POINT, (clip_y << 16) | clip_x);
p = pb_push1_to(SUBCH_CLASS_19, p, NV01_CONTEXT_CLIP_RECTANGLE_SET_SIZE, (clip_h << 16) | clip_w);
p = pb_push1_to(SUBCH_CLASS_19, p, NV01_CONTEXT_CLIP_RECTANGLE_SET_SIZE, (clip_height << 16) | clip_width);
p = pb_push1_to(SUBCH_CLASS_9F, p, NV_IMAGE_BLIT_CLIP_RECTANGLE, clip_rect_ctx_.ChannelID);
p = pb_push1_to(SUBCH_CLASS_9F, p, 0x0120, 0); // Sync read
p = pb_push1_to(SUBCH_CLASS_9F, p, 0x0124, 1); // Sync write
p = pb_push1_to(SUBCH_CLASS_9F, p, 0x0128, 2); // Modulo
p = pb_push1_to(SUBCH_CLASS_62, p, NV10_CONTEXT_SURFACES_2D_FORMAT, test.buffer_color_format);
p = pb_push1_to(SUBCH_CLASS_62, p, NV10_CONTEXT_SURFACES_2D_FORMAT, surface_format);
p = pb_push1_to(SUBCH_CLASS_62, p, NV10_CONTEXT_SURFACES_2D_PITCH, (dest_pitch << 16) | image_pitch_);
p = pb_push1_to(SUBCH_CLASS_62, p, NV10_CONTEXT_SURFACES_2D_OFFSET_SRC, 0);
p = pb_push1_to(SUBCH_CLASS_62, p, NV10_CONTEXT_SURFACES_2D_OFFSET_DST, 0);
p = pb_push1_to(SUBCH_CLASS_62, p, NV10_CONTEXT_SURFACES_2D_PITCH, source_pitch | (destination_pitch << 16));
p = pb_push1_to(SUBCH_CLASS_62, p, NV10_CONTEXT_SURFACES_2D_OFFSET_SRC, source_offset);
p = pb_push1_to(SUBCH_CLASS_62, p, NV10_CONTEXT_SURFACES_2D_OFFSET_DST, destination_offset);
p = pb_push1_to(SUBCH_CLASS_9F, p, NV_IMAGE_BLIT_COLOR_KEY, null_ctx_.ChannelID);
p = pb_push1_to(SUBCH_CLASS_9F, p, NV_IMAGE_BLIT_PATTERN, null_ctx_.ChannelID);
p = pb_push1_to(SUBCH_CLASS_9F, p, NV_IMAGE_BLIT_ROP5, null_ctx_.ChannelID);
if (test.blit_operation == NV09F_SET_OPERATION_SRCCOPY) {
if (operation == NV09F_SET_OPERATION_SRCCOPY) {
p = pb_push1_to(SUBCH_CLASS_9F, p, NV_IMAGE_BLIT_SET_BETA, null_ctx_.ChannelID);
} else {
p = set_beta(p, 0.85f);
p = pb_push1_to(SUBCH_CLASS_12, p, NV012_SET_BETA, beta);
p = pb_push1_to(SUBCH_CLASS_9F, p, NV_IMAGE_BLIT_SET_BETA, beta_ctx_.ChannelID);
}
p = pb_push1_to(SUBCH_CLASS_9F, p, NV_IMAGE_BLIT_SET_BETA4, null_ctx_.ChannelID);
p = pb_push1_to(SUBCH_CLASS_9F, p, NV_IMAGE_BLIT_POINT_IN, in_x | (in_y << 16)); // 0x300
p = pb_push1_to(SUBCH_CLASS_9F, p, NV_IMAGE_BLIT_POINT_OUT, out_x | (out_y << 16)); // 0x304
p = pb_push1_to(SUBCH_CLASS_9F, p, NV_IMAGE_BLIT_SIZE, width | (height << 16)); // 0x308
p = pb_push1_to(SUBCH_CLASS_9F, p, NV_IMAGE_BLIT_POINT_IN, source_x | (source_y << 16));
p = pb_push1_to(SUBCH_CLASS_9F, p, NV_IMAGE_BLIT_POINT_OUT, destination_x | (destination_y << 16));
p = pb_push1_to(SUBCH_CLASS_9F, p, NV_IMAGE_BLIT_SIZE, width | (height << 16));
pb_end(p);
}
void ImageBlitTests::Test(const BlitTest& test) {
host_.PrepareDraw(0x00660033);
uint32_t image_bytes = image_pitch_ * image_height_;
pb_set_dma_address(&image_src_dma_ctx_, source_image_, image_bytes - 1);
if (test.composite_first) {
pb_set_dma_address(&image_composite_dma_ctx_, compositing_image_, image_bytes - 1);
}
uint32_t clip_x = 0;
uint32_t clip_y = 0;
uint32_t clip_w = host_.GetFramebufferWidth();
uint32_t clip_h = host_.GetFramebufferHeight();
if (test.composite_first) {
Render2D(test.blit_operation, test.GetBeta(), image_src_dma_ctx_.ChannelID, image_composite_dma_ctx_.ChannelID,
test.buffer_color_format, image_pitch_, SOURCE_WIDTH << 2, 0, SOURCE_X, SOURCE_Y, 0, 0, 0, SOURCE_WIDTH,
SOURCE_HEIGHT, clip_x, clip_y, clip_w, clip_h);
while (pb_busy()) {
}
Render2D(NV09F_SET_OPERATION_SRCCOPY, 0, image_composite_dma_ctx_.ChannelID,
11, // DMA channel 11 - 0x1117
test.buffer_color_format, SOURCE_WIDTH << 2, host_.GetFramebufferWidth() << 2, 0, 0, 0, 0, DESTINATION_X,
DESTINATION_Y, SOURCE_WIDTH, SOURCE_HEIGHT, clip_x, clip_y, clip_w, clip_h);
} else {
Render2D(test.blit_operation, test.GetBeta(), image_src_dma_ctx_.ChannelID,
11, // DMA channel 11 - 0x1117
test.buffer_color_format, image_pitch_, 4 * host_.GetFramebufferWidth(), 0, SOURCE_X, SOURCE_Y, 0,
DESTINATION_X, DESTINATION_Y, SOURCE_WIDTH, SOURCE_HEIGHT, clip_x, clip_y, clip_w, clip_h);
}
std::string op_name = OperationName(test.blit_operation);
pb_print("Op: %s\n", op_name.c_str());
std::string color_format_name = ColorFormatName(test.buffer_color_format);
pb_print("BufFmt: %s\n", color_format_name.c_str());
if (test.blit_operation != NV09F_SET_OPERATION_SRCCOPY) {
pb_print("Beta: %d\n", test.GetBeta());
}
if (test.composite_first) {
pb_print("Composite\n");
}
pb_draw_text_screen();
std::string name = MakeTestName(test);
@ -176,11 +208,10 @@ void ImageBlitTests::Test(const BlitTest& test) {
}
std::string ImageBlitTests::MakeTestName(const BlitTest& test) {
std::string ret = "ImageBlit_";
ret += OperationName(test.blit_operation);
ret += "_";
ret += ColorFormatName(test.buffer_color_format);
return std::move(ret);
char buf[256] = {0};
snprintf(buf, 255, "ImageBlt_%s_%s_B%08X_C%s", OperationName(test.blit_operation).c_str(),
ColorFormatName(test.buffer_color_format).c_str(), test.GetBeta(), test.composite_first ? "Y" : "N");
return buf;
}
static std::string OperationName(uint32_t operation) {
@ -207,4 +238,25 @@ static std::string ColorFormatName(uint32_t format) {
char buf[16] = {0};
snprintf(buf, 15, "%X", format);
return buf;
}
}
uint32_t ImageBlitTests::BlitTest::GetBeta() const {
uint32_t int_val;
// Sets the beta factor. The parameter is a signed fixed-point number with a sign bit and 31 fractional bits.
// Note that negative values are clamped to 0, and only 8 fractional bits are actually implemented in hardware.
float beta_val = beta;
if (beta_val < 0.0f) {
int_val = 0;
} else {
if (beta_val > 1.0f) {
beta_val = 1.0f;
}
constexpr uint32_t kMaxValue = 0x7f800000;
int_val = static_cast<int>(beta_val * static_cast<float>(kMaxValue));
int_val &= kMaxValue;
}
return int_val;
}

View File

@ -12,6 +12,10 @@ class ImageBlitTests : public TestSuite {
struct BlitTest {
uint32_t blit_operation;
uint32_t buffer_color_format;
float beta;
bool composite_first;
uint32_t GetBeta() const;
};
public:
@ -22,17 +26,23 @@ class ImageBlitTests : public TestSuite {
void Deinitialize() override;
private:
void CreateGeometry();
void Test(const BlitTest& test);
void Render2D(uint32_t operation, uint32_t beta, uint32_t source_channel, uint32_t destination_channel,
uint32_t surface_format, uint32_t source_pitch, uint32_t destination_pitch, uint32_t source_offset,
uint32_t source_x, uint32_t source_y, uint32_t destination_offset, uint32_t destination_x,
uint32_t destination_y, uint32_t width, uint32_t height, uint32_t clip_x, uint32_t clip_y,
uint32_t clip_width, uint32_t clip_height);
static std::string MakeTestName(const BlitTest& test);
uint32_t image_pitch_;
uint32_t image_height_;
uint8_t* surface_memory_;
uint8_t* source_image_;
uint8_t* compositing_image_;
struct s_CtxDma null_ctx_;
struct s_CtxDma image_src_dma_ctx_;
struct s_CtxDma image_composite_dma_ctx_;
struct s_CtxDma clip_rect_ctx_;
struct s_CtxDma beta_ctx_;
};