Skip to content

Commit 6eb8df4

Browse files
committed
Fix matte registers with a lower X position and add units tests
1 parent 8edaf75 commit 6eb8df4

File tree

3 files changed

+149
-26
lines changed

3 files changed

+149
-26
lines changed

src/CDI/Video/RendererSIMD.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,11 @@ void RendererSIMD::HandleMatteSIMD() noexcept
627627
if(disregard || nextMatte0 >= m_matteControl.size())
628628
nextChange0 = m_screen.m_width;
629629
else
630+
{
630631
nextChange0 = matteXPosition(m_matteControl[nextMatte0]);
632+
if(nextChange0 <= x) // Sometimes the next register has a lower position.
633+
nextChange0 = m_screen.m_width;
634+
}
631635
}
632636
nextChange = nextChange0;
633637
}

src/CDI/Video/RendererSoftware.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ void RendererSoftware::HandleMatte(uint16_t pos) noexcept
468468
}
469469

470470
const uint32_t command = m_matteControl[m_nextMatte[PLANE]];
471-
if(matteXPosition(command) > pos)
471+
if(matteXPosition(command) != pos)
472472
return;
473473

474474
++m_nextMatte[PLANE];

tests/testRenderer.cpp

Lines changed: 144 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ inline constexpr Video::Pixel GREEN{0xFF'00'FF'00};
2121
inline constexpr Video::Pixel HALF_GREEN{0xFF'09'85'09};
2222
inline constexpr Video::Pixel HIDDEN_GREEN{0x00'00'FF'00};
2323
inline constexpr Video::Pixel MAGENTA{0xFF'FF'00'FF};
24-
inline constexpr Video::Pixel BLUE{0xFF'00'00'FF};
24+
inline constexpr Video::Pixel BLUE{0xFF'00'00'FF}; // Background color.
2525

2626
inline constexpr Video::ImagePlane PLANEA = Video::A;
2727
inline constexpr Video::ImagePlane PLANEB = Video::B;
@@ -156,7 +156,7 @@ static constexpr void configureOneMatte(Video::Renderer& renderer) noexcept
156156
renderer.m_matteNumber = false;
157157
renderer.m_icf[PLANEA] = 63;
158158
renderer.m_icf[PLANEB] = 63;
159-
// starts with matte flag false.
159+
// starts with matte flags false.
160160
renderer.m_matteControl[0] = makeCommand(0b0100, true, 63, 0); // ICF A 63.
161161
renderer.m_matteControl[1] = makeCommand(0b0110, true, 63, 1); // ICF B 63.
162162
renderer.m_matteControl[2] = makeCommand(0b0100, true, 31, 2); // ICF A 31.
@@ -177,7 +177,7 @@ static constexpr void configureTwoMattes(Video::Renderer& renderer) noexcept
177177
renderer.m_matteNumber = true;
178178
renderer.m_icf[PLANEA] = 63;
179179
renderer.m_icf[PLANEB] = 63;
180-
// starts with matte flag false.
180+
// starts with matte flags false.
181181
// mf bit must be ignored.
182182
renderer.m_matteControl[0] = makeCommand(0b1111, true, 31, 8); // Set matte flag 0, ICF B 31, plane B visible.
183183
renderer.m_matteControl[2] = makeCommand(0, true, 0, 3); // Ignore later commands.
@@ -200,6 +200,18 @@ static void configureCLUT(Video::Renderer& renderer) noexcept
200200
renderer.m_clut[128] = GREEN.AsU32();
201201
}
202202

203+
static constexpr std::array<uint8_t, 384> INPUT_A = [] () {
204+
std::array<uint8_t, 384> array{};
205+
std::ranges::fill(array, 0); // CLUT 0
206+
return array;
207+
}();
208+
209+
static constexpr std::array<uint8_t, 384> INPUT_B = [] () {
210+
std::array<uint8_t, 384> array{};
211+
std::ranges::fill(array, 0); // CLUT 0 + 128
212+
return array;
213+
}();
214+
203215
TEST_CASE("Matte", "[Video]")
204216
{
205217
Video::RendererSoftware rendererSoft;
@@ -213,17 +225,6 @@ TEST_CASE("Matte", "[Video]")
213225
configureCLUT(rendererSoft);
214226
IF_SIMD(configureCLUT(rendererSIMD))
215227

216-
constexpr std::array<uint8_t, 384> INPUT_A = [] () {
217-
std::array<uint8_t, 384> array{};
218-
std::ranges::fill(array, 0); // CLUT 0
219-
return array;
220-
}();
221-
constexpr std::array<uint8_t, 384> INPUT_B = [] () {
222-
std::array<uint8_t, 384> array{};
223-
std::ranges::fill(array, 0); // CLUT 0 + 128
224-
return array;
225-
}();
226-
227228
rendererSoft.DrawLine(INPUT_A.data(), INPUT_B.data(), 0);
228229
IF_SIMD(rendererSIMD.DrawLine(INPUT_A.data(), INPUT_B.data(), 0))
229230

@@ -265,17 +266,6 @@ TEST_CASE("Matte", "[Video]")
265266
configureCLUT(rendererSoft);
266267
IF_SIMD(configureCLUT(rendererSIMD))
267268

268-
constexpr std::array<uint8_t, 384> INPUT_A = [] () {
269-
std::array<uint8_t, 384> array{};
270-
std::ranges::fill(array, 0); // CLUT 0
271-
return array;
272-
}();
273-
constexpr std::array<uint8_t, 384> INPUT_B = [] () {
274-
std::array<uint8_t, 384> array{};
275-
std::ranges::fill(array, 0); // CLUT 0 + 128
276-
return array;
277-
}();
278-
279269
rendererSoft.DrawLine(INPUT_A.data(), INPUT_B.data(), 0);
280270
IF_SIMD(rendererSIMD.DrawLine(INPUT_A.data(), INPUT_B.data(), 0))
281271

@@ -311,6 +301,135 @@ TEST_CASE("Matte", "[Video]")
311301
}
312302
}
313303

304+
static constexpr void configureOneMatteLower(Video::Renderer& renderer) noexcept
305+
{
306+
renderer.m_transparencyControl[PLANEA] = 0b0100; // Matte flag 1 = true.
307+
renderer.m_transparencyControl[PLANEB] = 0b1000; // Never.
308+
renderer.m_mix = false;
309+
renderer.m_planeOrder = false; // A in front of B.
310+
311+
renderer.m_matteNumber = false;
312+
renderer.m_icf[PLANEA] = 63;
313+
renderer.m_icf[PLANEB] = 63;
314+
// starts with matte flags false.
315+
renderer.m_matteControl[0] = makeCommand(0b0100, true, 63, 0); // ICF A 63.
316+
renderer.m_matteControl[1] = makeCommand(0b0110, true, 63, 1); // ICF B 63.
317+
renderer.m_matteControl[2] = makeCommand(0b0100, true, 31, 2); // ICF A 31.
318+
renderer.m_matteControl[3] = makeCommand(0b1001, true, 0, 3); // Set matte flag 1, plane A hidden.
319+
renderer.m_matteControl[4] = makeCommand(0b0110, true, 31, 4); // ICF B 31.
320+
renderer.m_matteControl[5] = makeCommand(0b1000, true, 0, 5); // Reset matte flag 1, plane A visible.
321+
renderer.m_matteControl[6] = makeCommand(0b1000, true, 0, 5); // Not above previous command, must not infinite loop.
322+
renderer.m_matteControl[7] = makeCommand(0b0100, true, 0, 740); // ICF A 0, must be ignored.
323+
}
324+
325+
static constexpr void configureTwoMattesLower(Video::Renderer& renderer) noexcept
326+
{
327+
renderer.m_transparencyControl[PLANEA] = 0b1100; // Matte flag 1 = false.
328+
renderer.m_transparencyControl[PLANEB] = 0b1011; // Matte flag 0 = false.
329+
renderer.m_mix = false;
330+
renderer.m_planeOrder = true; // B in front of A.
331+
332+
renderer.m_matteNumber = true;
333+
renderer.m_icf[PLANEA] = 63;
334+
renderer.m_icf[PLANEB] = 63;
335+
// starts with matte flags false.
336+
// mf bit must be ignored.
337+
renderer.m_matteControl[0] = makeCommand(0b1111, true, 31, 1); // Set matte flag 0, ICF B 31, plane B visible.
338+
renderer.m_matteControl[2] = makeCommand(0b1111, true, 0, 1); // Ignore later commands.
339+
renderer.m_matteControl[3] = makeCommand(0b1000, true, 0, 2); // ICF B 0, must be ignored.
340+
renderer.m_matteControl[3] = makeCommand(0, true, 63, 3); // ICF B 63, must be ignored.
341+
342+
renderer.m_matteControl[4] = makeCommand(0b1101, false, 63, 2); // Set matte flag 1, ICF A 63, plane A visible.
343+
renderer.m_matteControl[5] = makeCommand(0b0100, false, 31, 4); // ICF A 31.
344+
renderer.m_matteControl[6] = makeCommand(0b0100, false, 63, 4); // Ignored.
345+
renderer.m_matteControl[7] = makeCommand(0b0110, false, 63, 8); // ICF B 63, ignored.
346+
}
347+
348+
TEST_CASE("Matte lower position", "[Video]")
349+
{
350+
// Tests the case where a next matte control register has a lower position than the next one.
351+
Video::RendererSoftware rendererSoft;
352+
IF_SIMD(Video::RendererSIMD rendererSIMD)
353+
354+
SECTION("One matte")
355+
{
356+
configureOneMatteLower(rendererSoft);
357+
IF_SIMD(configureOneMatteLower(rendererSIMD))
358+
359+
configureCLUT(rendererSoft);
360+
IF_SIMD(configureCLUT(rendererSIMD))
361+
362+
rendererSoft.DrawLine(INPUT_A.data(), INPUT_B.data(), 0);
363+
IF_SIMD(rendererSIMD.DrawLine(INPUT_A.data(), INPUT_B.data(), 0))
364+
365+
constexpr std::array<Video::Pixel, 768> EXPECTED_A = [] () {
366+
std::array<Video::Pixel, 768> array{RED, RED, RED, HIDDEN_RED, HIDDEN_RED};
367+
std::fill(array.begin() + 5, array.end(), RED);
368+
return array;
369+
}();
370+
constexpr std::array<Video::Pixel, 768> EXPECTED_B = [] () {
371+
std::array<Video::Pixel, 768> array;
372+
std::ranges::fill(array, GREEN);
373+
return array;
374+
}();
375+
constexpr std::array<Video::Pixel, 768> EXPECTED_SCREEN = [] () {
376+
std::array<Video::Pixel, 768> array{
377+
RED, RED, HALF_RED, GREEN, HALF_GREEN,
378+
};
379+
std::fill(array.begin() + 5, array.end(), HALF_RED);
380+
return array;
381+
}();
382+
383+
REQUIRE(std::equal(EXPECTED_A.cbegin(), EXPECTED_A.cend(), rendererSoft.m_plane[PLANEA].GetLinePointer(0)));
384+
IF_SIMD(REQUIRE(std::equal(EXPECTED_A.cbegin(), EXPECTED_A.cend(), rendererSIMD.m_plane[PLANEA].GetLinePointer(0))))
385+
386+
REQUIRE(std::equal(EXPECTED_B.cbegin(), EXPECTED_B.cend(), rendererSoft.m_plane[PLANEB].GetLinePointer(0)));
387+
IF_SIMD(REQUIRE(std::equal(EXPECTED_B.cbegin(), EXPECTED_B.cend(), rendererSIMD.m_plane[PLANEB].GetLinePointer(0))))
388+
389+
REQUIRE(std::equal(EXPECTED_SCREEN.cbegin(), EXPECTED_SCREEN.cend(), rendererSoft.m_screen.GetLinePointer(0)));
390+
IF_SIMD(REQUIRE(std::equal(EXPECTED_SCREEN.cbegin(), EXPECTED_SCREEN.cend(), rendererSIMD.m_screen.GetLinePointer(0))))
391+
}
392+
393+
SECTION("Two matte")
394+
{
395+
configureTwoMattesLower(rendererSoft);
396+
IF_SIMD(configureTwoMattesLower(rendererSIMD))
397+
398+
configureCLUT(rendererSoft);
399+
IF_SIMD(configureCLUT(rendererSIMD))
400+
401+
rendererSoft.DrawLine(INPUT_A.data(), INPUT_B.data(), 0);
402+
IF_SIMD(rendererSIMD.DrawLine(INPUT_A.data(), INPUT_B.data(), 0))
403+
404+
constexpr std::array<Video::Pixel, 768> EXPECTED_A = [] () {
405+
std::array<Video::Pixel, 768> array{
406+
HIDDEN_RED, HIDDEN_RED,
407+
};
408+
std::fill(array.begin() + 2, array.end(), RED);
409+
return array;
410+
}();
411+
constexpr std::array<Video::Pixel, 768> EXPECTED_B = [] () {
412+
std::array<Video::Pixel, 768> array{HIDDEN_GREEN};
413+
std::fill(array.begin() + 1, array.end(), GREEN);
414+
return array;
415+
}();
416+
constexpr std::array<Video::Pixel, 768> EXPECTED_SCREEN = [] () {
417+
std::array<Video::Pixel, 768> array{BLUE};
418+
std::fill(array.begin() + 1, array.end(), HALF_GREEN);
419+
return array;
420+
}();
421+
422+
REQUIRE(std::equal(EXPECTED_A.cbegin(), EXPECTED_A.cend(), rendererSoft.m_plane[PLANEA].GetLinePointer(0)));
423+
IF_SIMD(REQUIRE(std::equal(EXPECTED_A.cbegin(), EXPECTED_A.cend(), rendererSIMD.m_plane[PLANEA].GetLinePointer(0))))
424+
425+
REQUIRE(std::equal(EXPECTED_B.cbegin(), EXPECTED_B.cend(), rendererSoft.m_plane[PLANEB].GetLinePointer(0)));
426+
IF_SIMD(REQUIRE(std::equal(EXPECTED_B.cbegin(), EXPECTED_B.cend(), rendererSIMD.m_plane[PLANEB].GetLinePointer(0))))
427+
428+
REQUIRE(std::equal(EXPECTED_SCREEN.cbegin(), EXPECTED_SCREEN.cend(), rendererSoft.m_screen.GetLinePointer(0)));
429+
IF_SIMD(REQUIRE(std::equal(EXPECTED_SCREEN.cbegin(), EXPECTED_SCREEN.cend(), rendererSIMD.m_screen.GetLinePointer(0))))
430+
}
431+
}
432+
314433
TEST_CASE("Decoding length", "[Video]")
315434
{
316435
Video::RendererSoftware rendererSoft;

0 commit comments

Comments
 (0)