Refactoring #3

Merged
itten merged 87 commits from refactoring into main 2026-09-01 23:52:36 +03:00
2 changed files with 189 additions and 6 deletions
Showing only changes of commit 4ffbf0266c - Show all commits
+67 -6
View File
@@ -3,17 +3,20 @@ package renderer
import (
"errors"
"fmt"
"mxl-player/internal/sdl"
"unsafe"
"mxl-player/internal/sdl"
"github.com/christerso/vulkan-go/vk"
)
// Raises by swapchain creation, whem windos is minimized
var ErrMinimized = errors.New("window minimized")
// ErrOutOfDate is returned by DrawFrame when the swapchain needs recreation.
var ErrOutOfDate = errors.New("swapchain out of date")
var (
// Raises by swapchain creation, whem windos is minimized
ErrMinimized = errors.New("window minimized")
// ErrOutOfDate is returned by DrawFrame when the swapchain needs recreation.
ErrOutOfDate = errors.New("swapchain out of date")
ErrInvalidVideoFrame = errors.New("invalid video frame")
)
// shader push-constants block
type PushConstants struct {
@@ -392,6 +395,64 @@ func (r *Renderer) RecreateBuffers(newSize vk.DeviceSize) error {
return nil
}
func (r *Renderer) StageFrame(
payload []byte,
width uint32,
height uint32,
stride uint32,
) error {
frameSize, err := validateFramePayload(len(payload), width, height, stride)
if err != nil {
return err
}
if frameSize != r.FrameSize() {
// RecreateBuffers waits for the device to become idle.
if err := r.RecreateBuffers(frameSize); err != nil {
return fmt.Errorf("resize video buffers: %w", err)
}
} else {
// The previous submitted frame may still read the mapped staging buffer.
if err := r.dev.WaitFence(r.inFlight, ^uint64(0)); err != nil {
return fmt.Errorf("wait before staging video: %w", err)
}
}
vk.CopyToMapped(
r.StagingMapped(),
payload[:int(frameSize)],
)
return nil
}
func validateFramePayload(
payloadLen int,
width uint32,
height uint32,
stride uint32,
) (vk.DeviceSize, error) {
if width == 0 || height == 0 || stride == 0 {
return 0, fmt.Errorf(
"%w: dimensions=%dx%d stride=%d",
ErrInvalidVideoFrame,
width,
height,
stride,
)
}
requiredSize := uint64(stride) * uint64(height)
if payloadLen < 0 || requiredSize > uint64(payloadLen) {
return 0, fmt.Errorf(
"%w: payload=%d required=%d",
ErrInvalidVideoFrame,
payloadLen,
requiredSize,
)
}
return vk.DeviceSize(requiredSize), nil
}
// DrawFrame acquires an image, records commands, submits, and presents.
// Returns ErrOutOfDate if the swapchain needs recreation
func (r *Renderer) DrawFrame(videoW, videoH, stride uint32) error {
+122
View File
@@ -0,0 +1,122 @@
package renderer
import (
"errors"
"strconv"
"testing"
"github.com/christerso/vulkan-go/vk"
)
func TestValidateFramePayload(t *testing.T) {
tests := []struct {
name string
payloadLen int
width uint32
height uint32
stride uint32
wantSize vk.DeviceSize
wantErr bool
}{
{
name: "valid frame",
payloadLen: 5120 * 1080,
width: 1920,
height: 1080,
stride: 5120,
wantSize: vk.DeviceSize(5120 * 1080),
},
{
name: "payload may be larger than frame",
payloadLen: 5120*1080 + 128,
width: 1920,
height: 1080,
stride: 5120,
wantSize: vk.DeviceSize(5120 * 1080),
},
{
name: "zero width",
payloadLen: 100,
height: 10,
stride: 10,
wantErr: true,
},
{
name: "zero height",
payloadLen: 100,
width: 10,
stride: 10,
wantErr: true,
},
{
name: "zero stride",
payloadLen: 100,
width: 10,
height: 10,
wantErr: true,
},
{
name: "payload is too small",
payloadLen: 99,
width: 10,
height: 10,
stride: 10,
wantErr: true,
},
{
name: "negative payload length",
payloadLen: -1,
width: 10,
height: 10,
stride: 10,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := validateFramePayload(
tt.payloadLen,
tt.width,
tt.height,
tt.stride,
)
if tt.wantErr {
if !errors.Is(err, ErrInvalidVideoFrame) {
t.Fatalf("validateFramePayload() error = %v, want %v", err, ErrInvalidVideoFrame)
}
return
}
if err != nil {
t.Fatalf("validateFramePayload() error = %v, want nil", err)
}
if got != tt.wantSize {
t.Errorf("validateFramePayload() size = %d, want %d", got, tt.wantSize)
}
})
}
}
func TestValidateFramePayloadUses64BitSize(t *testing.T) {
if strconv.IntSize < 64 {
t.Skip("test requires a 64-bit int")
}
stride := ^uint32(0)
height := uint32(2)
required := uint64(stride) * uint64(height)
got, err := validateFramePayload(
int(required),
1,
height,
stride,
)
if err != nil {
t.Fatalf("validateFramePayload() error = %v, want nil", err)
}
if uint64(got) != required {
t.Fatalf("validateFramePayload() size = %d, want %d", got, required)
}
}