mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'master' (early part) into medusa
This commit is contained in:
commit
23609b4a88
13
CHANGES
13
CHANGES
|
@ -23,17 +23,28 @@ Features:
|
|||
- Improved logging configuration
|
||||
- One-Player BattleChip/Progress/Beast Link Gate support
|
||||
- Add Game Boy Color palettes for original Game Boy games
|
||||
Bugfixes:
|
||||
- Debugger: Add unary operators and memory dereferencing
|
||||
- GB: Expose platform information to CLI debugger
|
||||
Emulation fixes:
|
||||
- GBA: All IRQs have 7 cycle delay (fixes mgba.io/i/539, mgba.io/i/1208)
|
||||
- GBA: Reset now reloads multiboot ROMs
|
||||
- GBA BIOS: Fix multiboot entry point (fixes Magic Floor)
|
||||
- GB Video: Delay LYC STAT check (fixes mgba.io/i/1331)
|
||||
- GB Video: Fix window being enabled mid-scanline (fixes mgba.io/i/1328)
|
||||
- GB I/O: Filter IE top bits properly (fixes mgba.io/i/1329)
|
||||
Other fixes:
|
||||
- Qt: More app metadata fixes
|
||||
- Qt: Fix load recent from archive (fixes mgba.io/i/1325)
|
||||
- LR35902: Fix disassembly of several CB-prefix instructions
|
||||
Misc:
|
||||
- GBA Savedata: EEPROM performance fixes
|
||||
- GBA Savedata: Automatically map 1Mbit Flash files as 1Mbit Flash
|
||||
- GB Memory: Support running from blocked memory
|
||||
- Qt: Don't unload ROM immediately if it crashes
|
||||
- Debugger: Add breakpoint and watchpoint listing
|
||||
- Qt: Add missing HEVC NVENC option (fixes mgba.io/i/1323)
|
||||
- LR35902: Support PC-relative opcode decoding
|
||||
- Qt: Improve camera initialization
|
||||
|
||||
0.7.1: (2019-02-24)
|
||||
Bugfixes:
|
||||
|
|
|
@ -765,6 +765,7 @@ if(M_CORE_GB)
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/src/lr35902/debugger/debugger.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/lr35902/debugger/memory-debugger.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/gb/debugger/cli.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/gb/debugger/debugger.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/gb/debugger/symbols.c)
|
||||
list(APPEND TEST_SRC
|
||||
${LR35902_TEST_SRC}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
Binary file not shown.
|
@ -38,6 +38,7 @@ enum Operation {
|
|||
OP_NOT,
|
||||
OP_SHIFT_L,
|
||||
OP_SHIFT_R,
|
||||
OP_DEREFERENCE,
|
||||
};
|
||||
|
||||
struct Token {
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/* Copyright (c) 2013-2019 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef GB_DEBUGGER_H
|
||||
#define GB_DEBUGGER_H
|
||||
|
||||
#include <mgba-util/common.h>
|
||||
|
||||
CXX_GUARD_START
|
||||
|
||||
struct GB;
|
||||
struct mDebuggerPlatform;
|
||||
|
||||
struct mDebuggerPlatform* GBDebuggerCreate(struct GB* gb);
|
||||
|
||||
CXX_GUARD_END
|
||||
|
||||
#endif
|
|
@ -32,7 +32,9 @@ struct GBVideoSoftwareRenderer {
|
|||
uint8_t wy;
|
||||
uint8_t wx;
|
||||
uint8_t currentWy;
|
||||
uint8_t currentWx;
|
||||
int lastY;
|
||||
int lastX;
|
||||
bool hasWindow;
|
||||
|
||||
GBRegisterLCDC lcdc;
|
||||
|
|
|
@ -20,6 +20,7 @@ struct LR35902Segment {
|
|||
const char* name;
|
||||
};
|
||||
|
||||
struct CLIDebuggerSystem;
|
||||
struct LR35902Debugger {
|
||||
struct mDebuggerPlatform d;
|
||||
struct LR35902Core* cpu;
|
||||
|
@ -31,6 +32,8 @@ struct LR35902Debugger {
|
|||
ssize_t nextId;
|
||||
|
||||
const struct LR35902Segment* segments;
|
||||
|
||||
void (*printStatus)(struct CLIDebuggerSystem*);
|
||||
};
|
||||
|
||||
struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void);
|
||||
|
|
|
@ -86,6 +86,7 @@ enum {
|
|||
LR35902_OP_FLAG_MEMORY = 2,
|
||||
LR35902_OP_FLAG_INCREMENT = 4,
|
||||
LR35902_OP_FLAG_DECREMENT = 8,
|
||||
LR35902_OP_FLAG_RELATIVE = 16,
|
||||
};
|
||||
|
||||
struct LR35902Operand {
|
||||
|
@ -104,7 +105,7 @@ struct LR35902InstructionInfo {
|
|||
};
|
||||
|
||||
size_t LR35902Decode(uint8_t opcode, struct LR35902InstructionInfo* info);
|
||||
int LR35902Disassemble(struct LR35902InstructionInfo* info, char* buffer, int blen);
|
||||
int LR35902Disassemble(struct LR35902InstructionInfo* info, uint16_t pc, char* buffer, int blen);
|
||||
|
||||
CXX_GUARD_END
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include <mgba/internal/debugger/parser.h>
|
||||
|
||||
#include <mgba/core/core.h>
|
||||
#include <mgba/debugger/debugger.h>
|
||||
#include <mgba-util/string.h>
|
||||
|
||||
|
@ -89,52 +90,77 @@ static void _lexOperator(struct LexVector* lv, char operator, enum LexState* sta
|
|||
break;
|
||||
}
|
||||
*state = LEX_ERROR;
|
||||
}
|
||||
if (*state == LEX_ROOT || *state == LEX_ERROR) {
|
||||
struct Token lvNext;
|
||||
lvNext.type = TOKEN_OPERATOR_TYPE;
|
||||
*state = LEX_ROOT;
|
||||
switch (operator) {
|
||||
case '-':
|
||||
lvNext.operatorValue = OP_NEGATE;
|
||||
break;
|
||||
case '~':
|
||||
lvNext.operatorValue = OP_FLIP;
|
||||
break;
|
||||
case '!':
|
||||
lvNext.operatorValue = OP_NOT;
|
||||
break;
|
||||
case '*':
|
||||
lvNext.operatorValue = OP_DEREFERENCE;
|
||||
break;
|
||||
default:
|
||||
lvNext.type = TOKEN_ERROR_TYPE;
|
||||
*state = LEX_ERROR;
|
||||
return;
|
||||
}
|
||||
*LexVectorAppend(lv) = lvNext;
|
||||
return;
|
||||
}
|
||||
struct Token* lvNext = LexVectorAppend(lv);
|
||||
lvNext->type = TOKEN_OPERATOR_TYPE;
|
||||
*state = LEX_EXPECT_OPERATOR2;
|
||||
struct Token lvNext;
|
||||
lvNext.type = TOKEN_OPERATOR_TYPE;
|
||||
switch (operator) {
|
||||
case '=':
|
||||
lvNext->operatorValue = OP_ASSIGN;
|
||||
lvNext.operatorValue = OP_ASSIGN;
|
||||
break;
|
||||
case '+':
|
||||
lvNext->operatorValue = OP_ADD;
|
||||
lvNext.operatorValue = OP_ADD;
|
||||
break;
|
||||
case '-':
|
||||
lvNext->operatorValue = OP_SUBTRACT;
|
||||
lvNext.operatorValue = OP_SUBTRACT;
|
||||
break;
|
||||
case '*':
|
||||
lvNext->operatorValue = OP_MULTIPLY;
|
||||
lvNext.operatorValue = OP_MULTIPLY;
|
||||
break;
|
||||
case '/':
|
||||
lvNext->operatorValue = OP_DIVIDE;
|
||||
lvNext.operatorValue = OP_DIVIDE;
|
||||
break;
|
||||
case '%':
|
||||
lvNext->operatorValue = OP_MODULO;
|
||||
lvNext.operatorValue = OP_MODULO;
|
||||
break;
|
||||
case '&':
|
||||
lvNext->operatorValue = OP_AND;
|
||||
lvNext.operatorValue = OP_AND;
|
||||
break;
|
||||
case '|':
|
||||
lvNext->operatorValue = OP_OR;
|
||||
lvNext.operatorValue = OP_OR;
|
||||
break;
|
||||
case '^':
|
||||
lvNext->operatorValue = OP_XOR;
|
||||
lvNext.operatorValue = OP_XOR;
|
||||
break;
|
||||
case '<':
|
||||
lvNext->operatorValue = OP_LESS;
|
||||
lvNext.operatorValue = OP_LESS;
|
||||
break;
|
||||
case '>':
|
||||
lvNext->operatorValue = OP_GREATER;
|
||||
lvNext.operatorValue = OP_GREATER;
|
||||
break;
|
||||
case '!':
|
||||
lvNext->operatorValue = OP_NOT;
|
||||
lvNext.operatorValue = OP_NOT;
|
||||
break;
|
||||
default:
|
||||
lvNext->type = TOKEN_ERROR_TYPE;
|
||||
break;
|
||||
*state = LEX_ERROR;
|
||||
return;
|
||||
}
|
||||
*state = LEX_EXPECT_OPERATOR2;
|
||||
*LexVectorAppend(lv) = lvNext;
|
||||
}
|
||||
|
||||
static void _lexValue(struct LexVector* lv, char token, uint32_t next, enum LexState* state) {
|
||||
|
@ -247,6 +273,12 @@ size_t lexExpression(struct LexVector* lv, const char* string, size_t length, co
|
|||
lvNext = LexVectorAppend(lv);
|
||||
lvNext->type = TOKEN_OPEN_PAREN_TYPE;
|
||||
break;
|
||||
case '!':
|
||||
case '-':
|
||||
case '~':
|
||||
case '*':
|
||||
_lexOperator(lv, token, &state);
|
||||
break;
|
||||
case ' ':
|
||||
case '\t':
|
||||
break;
|
||||
|
@ -499,6 +531,7 @@ static const int _operatorPrecedence[] = {
|
|||
[OP_NOT] = 2,
|
||||
[OP_SHIFT_L] = 5,
|
||||
[OP_SHIFT_R] = 5,
|
||||
[OP_DEREFERENCE] = 2,
|
||||
};
|
||||
|
||||
static struct ParseTree* _parseTreeCreate() {
|
||||
|
@ -622,7 +655,7 @@ void parseFree(struct ParseTree* tree) {
|
|||
}
|
||||
}
|
||||
|
||||
static bool _performOperation(enum Operation operation, int32_t current, int32_t next, int32_t* value) {
|
||||
static bool _performOperation(struct mDebugger* debugger, enum Operation operation, int32_t current, int32_t next, int32_t* value, int* segment) {
|
||||
switch (operation) {
|
||||
case OP_ASSIGN:
|
||||
current = next;
|
||||
|
@ -683,12 +716,29 @@ static bool _performOperation(enum Operation operation, int32_t current, int32_t
|
|||
case OP_GE:
|
||||
current = current >= next;
|
||||
break;
|
||||
case OP_NEGATE:
|
||||
current = -next;
|
||||
break;
|
||||
case OP_FLIP:
|
||||
current = ~next;
|
||||
break;
|
||||
case OP_NOT:
|
||||
current = !next;
|
||||
break;
|
||||
case OP_SHIFT_L:
|
||||
current <<= next;
|
||||
break;
|
||||
case OP_SHIFT_R:
|
||||
current >>= next;
|
||||
break;
|
||||
case OP_DEREFERENCE:
|
||||
if (*segment < 0) {
|
||||
current = debugger->core->busRead8(debugger->core, next);
|
||||
} else {
|
||||
current = debugger->core->rawRead8(debugger->core, next, *segment);
|
||||
}
|
||||
*segment = -1;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -714,13 +764,37 @@ bool mDebuggerEvaluateParseTree(struct mDebugger* debugger, struct ParseTree* tr
|
|||
}
|
||||
return mDebuggerEvaluateParseTree(debugger, tree->lhs, segment, NULL);
|
||||
case TOKEN_OPERATOR_TYPE:
|
||||
if (!mDebuggerEvaluateParseTree(debugger, tree->lhs, &lhs, segment)) {
|
||||
return false;
|
||||
switch (tree->token.operatorValue) {
|
||||
case OP_ASSIGN:
|
||||
case OP_ADD:
|
||||
case OP_SUBTRACT:
|
||||
case OP_MULTIPLY:
|
||||
case OP_DIVIDE:
|
||||
case OP_MODULO:
|
||||
case OP_AND:
|
||||
case OP_OR:
|
||||
case OP_XOR:
|
||||
case OP_LESS:
|
||||
case OP_GREATER:
|
||||
case OP_EQUAL:
|
||||
case OP_NOT_EQUAL:
|
||||
case OP_LOGICAL_AND:
|
||||
case OP_LOGICAL_OR:
|
||||
case OP_LE:
|
||||
case OP_GE:
|
||||
case OP_SHIFT_L:
|
||||
case OP_SHIFT_R:
|
||||
if (!mDebuggerEvaluateParseTree(debugger, tree->lhs, &lhs, segment)) {
|
||||
return false;
|
||||
}
|
||||
// Fall through
|
||||
default:
|
||||
if (!mDebuggerEvaluateParseTree(debugger, tree->rhs, &rhs, segment)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!mDebuggerEvaluateParseTree(debugger, tree->rhs, &rhs, segment)) {
|
||||
return false;
|
||||
}
|
||||
return _performOperation(tree->token.operatorValue, lhs, rhs, value);
|
||||
return _performOperation(debugger, tree->token.operatorValue, lhs, rhs, value, segment);
|
||||
case TOKEN_IDENTIFIER_TYPE:
|
||||
return mDebuggerLookupIdentifier(debugger, tree->token.identifierValue, value, segment);
|
||||
case TOKEN_ERROR_TYPE:
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <mgba/core/core.h>
|
||||
#include <mgba/internal/debugger/symbols.h>
|
||||
#include <mgba/internal/gb/cheats.h>
|
||||
#include <mgba/internal/gb/debugger/debugger.h>
|
||||
#include <mgba/internal/gb/debugger/symbols.h>
|
||||
#include <mgba/internal/gb/extra/cli.h>
|
||||
#include <mgba/internal/gb/io.h>
|
||||
|
@ -42,20 +43,6 @@ static const struct mCoreChannelInfo _GBAudioChannels[] = {
|
|||
{ 3, "ch4", "Channel 4", "Noise" },
|
||||
};
|
||||
|
||||
static const struct LR35902Segment _GBSegments[] = {
|
||||
{ .name = "ROM", .start = GB_BASE_CART_BANK1, .end = GB_BASE_VRAM },
|
||||
{ .name = "RAM", .start = GB_BASE_EXTERNAL_RAM, .end = GB_BASE_WORKING_RAM_BANK0 },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static const struct LR35902Segment _GBCSegments[] = {
|
||||
{ .name = "ROM", .start = GB_BASE_CART_BANK1, .end = GB_BASE_VRAM },
|
||||
{ .name = "RAM", .start = GB_BASE_EXTERNAL_RAM, .end = GB_BASE_WORKING_RAM_BANK0 },
|
||||
{ .name = "WRAM", .start = GB_BASE_WORKING_RAM_BANK1, .end = 0xE000 },
|
||||
{ .name = "VRAM", .start = GB_BASE_VRAM, .end = GB_BASE_EXTERNAL_RAM },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static const struct mCoreMemoryBlock _GBMemoryBlocks[] = {
|
||||
{ -1, "mem", "All", "All", 0, 0x10000, 0x10000, mCORE_MEMORY_VIRTUAL },
|
||||
{ GB_REGION_CART_BANK0, "cart0", "ROM Bank", "Game Pak (32kiB)", GB_BASE_CART_BANK0, GB_SIZE_CART_BANK0 * 2, 0x800000, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED, 511 },
|
||||
|
@ -715,12 +702,7 @@ static struct mDebuggerPlatform* _GBCoreDebuggerPlatform(struct mCore* core) {
|
|||
struct GBCore* gbcore = (struct GBCore*) core;
|
||||
struct GB* gb = core->board;
|
||||
if (!gbcore->debuggerPlatform) {
|
||||
struct LR35902Debugger* platform = (struct LR35902Debugger*) LR35902DebuggerPlatformCreate();
|
||||
if (gb->model >= GB_MODEL_CGB) {
|
||||
platform->segments = _GBCSegments;
|
||||
} else {
|
||||
platform->segments = _GBSegments;
|
||||
}
|
||||
struct LR35902Debugger* platform = (struct LR35902Debugger*) GBDebuggerCreate(gb);
|
||||
gbcore->debuggerPlatform = &platform->d;
|
||||
}
|
||||
return gbcore->debuggerPlatform;
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/* Copyright (c) 2013-2019 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include <mgba/internal/gb/debugger/debugger.h>
|
||||
|
||||
#include <mgba/core/core.h>
|
||||
#include <mgba/internal/debugger/cli-debugger.h>
|
||||
#include <mgba/internal/gb/gb.h>
|
||||
#include <mgba/internal/gb/io.h>
|
||||
#include <mgba/internal/gb/memory.h>
|
||||
#include <mgba/internal/lr35902/debugger/debugger.h>
|
||||
|
||||
static const struct LR35902Segment _GBSegments[] = {
|
||||
{ .name = "ROM", .start = GB_BASE_CART_BANK1, .end = GB_BASE_VRAM },
|
||||
{ .name = "RAM", .start = GB_BASE_EXTERNAL_RAM, .end = GB_BASE_WORKING_RAM_BANK0 },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static const struct LR35902Segment _GBCSegments[] = {
|
||||
{ .name = "ROM", .start = GB_BASE_CART_BANK1, .end = GB_BASE_VRAM },
|
||||
{ .name = "RAM", .start = GB_BASE_EXTERNAL_RAM, .end = GB_BASE_WORKING_RAM_BANK0 },
|
||||
{ .name = "WRAM", .start = GB_BASE_WORKING_RAM_BANK1, .end = 0xE000 },
|
||||
{ .name = "VRAM", .start = GB_BASE_VRAM, .end = GB_BASE_EXTERNAL_RAM },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static void _printStatus(struct CLIDebuggerSystem* debugger) {
|
||||
struct CLIDebuggerBackend* be = debugger->p->backend;
|
||||
struct GB* gb = debugger->p->d.core->board;
|
||||
be->printf(be, "IE: %02X IF: %02X IME: %i\n", gb->memory.ie, gb->memory.io[REG_IF], gb->memory.ime);
|
||||
be->printf(be, "LCDC: %02X STAT: %02X LY: %02X\n", gb->memory.io[REG_LCDC], gb->memory.io[REG_STAT] | 0x80, gb->memory.io[REG_LY]);
|
||||
be->printf(be, "Next video mode: %i\n", mTimingUntil(&gb->timing, &gb->video.modeEvent) / 4);
|
||||
}
|
||||
|
||||
struct mDebuggerPlatform* GBDebuggerCreate(struct GB* gb) {
|
||||
struct LR35902Debugger* platform = (struct LR35902Debugger*) LR35902DebuggerPlatformCreate();
|
||||
if (gb->model >= GB_MODEL_CGB) {
|
||||
platform->segments = _GBCSegments;
|
||||
} else {
|
||||
platform->segments = _GBSegments;
|
||||
}
|
||||
platform->printStatus = _printStatus;
|
||||
return &platform->d;
|
||||
}
|
|
@ -630,7 +630,7 @@ void GBDetectModel(struct GB* gb) {
|
|||
}
|
||||
|
||||
void GBUpdateIRQs(struct GB* gb) {
|
||||
int irqs = gb->memory.ie & gb->memory.io[REG_IF];
|
||||
int irqs = gb->memory.ie & gb->memory.io[REG_IF] & 0x1F;
|
||||
if (!irqs) {
|
||||
gb->cpu->irqPending = false;
|
||||
return;
|
||||
|
|
|
@ -190,7 +190,9 @@ static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer, enum G
|
|||
softwareRenderer->scx = 0;
|
||||
softwareRenderer->wy = 0;
|
||||
softwareRenderer->currentWy = 0;
|
||||
softwareRenderer->currentWx = 0;
|
||||
softwareRenderer->lastY = GB_VIDEO_VERTICAL_PIXELS;
|
||||
softwareRenderer->lastX = 0;
|
||||
softwareRenderer->hasWindow = false;
|
||||
softwareRenderer->wx = 0;
|
||||
softwareRenderer->model = model;
|
||||
|
@ -232,6 +234,9 @@ static void GBVideoSoftwareRendererUpdateWindow(struct GBVideoSoftwareRenderer*
|
|||
renderer->currentWy = GB_VIDEO_VERTICAL_PIXELS;
|
||||
} else {
|
||||
renderer->currentWy = renderer->lastY - renderer->wy;
|
||||
if (renderer->lastY == renderer->wy && renderer->lastX > renderer->wx) {
|
||||
++renderer->currentWy;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
renderer->currentWy += renderer->lastY;
|
||||
|
@ -489,6 +494,7 @@ static void GBVideoSoftwareRendererWriteOAM(struct GBVideoRenderer* renderer, ui
|
|||
static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj* obj, size_t oamMax) {
|
||||
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
|
||||
softwareRenderer->lastY = y;
|
||||
softwareRenderer->lastX = endX;
|
||||
uint8_t* maps = &softwareRenderer->d.vram[GB_BASE_MAP];
|
||||
if (GBRegisterLCDCIsTileMap(softwareRenderer->lcdc)) {
|
||||
maps += GB_SIZE_MAP;
|
||||
|
@ -498,9 +504,10 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
|
|||
}
|
||||
if (GBRegisterLCDCIsBgEnable(softwareRenderer->lcdc) || softwareRenderer->model >= GB_MODEL_CGB) {
|
||||
int wy = softwareRenderer->wy + softwareRenderer->currentWy;
|
||||
if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && wy <= y && endX >= softwareRenderer->wx - 7) {
|
||||
if (softwareRenderer->wx - 7 > 0 && !softwareRenderer->d.disableBG) {
|
||||
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, softwareRenderer->wx - 7, softwareRenderer->scx - softwareRenderer->offsetScx, softwareRenderer->scy + y - softwareRenderer->offsetScy);
|
||||
int wx = softwareRenderer->wx + softwareRenderer->currentWx - 7;
|
||||
if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && wy <= y && wx <= endX) {
|
||||
if (wx > 0 && !softwareRenderer->d.disableBG) {
|
||||
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, wx, softwareRenderer->scx - softwareRenderer->offsetScx, softwareRenderer->scy + y - softwareRenderer->offsetScy);
|
||||
}
|
||||
|
||||
maps = &softwareRenderer->d.vram[GB_BASE_MAP];
|
||||
|
@ -508,7 +515,7 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
|
|||
maps += GB_SIZE_MAP;
|
||||
}
|
||||
if (!softwareRenderer->d.disableWIN) {
|
||||
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, softwareRenderer->wx - 7, endX, 7 - softwareRenderer->wx - softwareRenderer->offsetWx, y - wy - softwareRenderer->offsetWy);
|
||||
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, wx, endX, -wx - softwareRenderer->offsetWx, y - wy - softwareRenderer->offsetWy);
|
||||
}
|
||||
} else if (!softwareRenderer->d.disableBG) {
|
||||
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, endX, softwareRenderer->scx - softwareRenderer->offsetScx, softwareRenderer->scy + y - softwareRenderer->offsetScy);
|
||||
|
@ -612,6 +619,9 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
|
|||
static void GBVideoSoftwareRendererFinishScanline(struct GBVideoRenderer* renderer, int y) {
|
||||
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
|
||||
|
||||
softwareRenderer->lastX = 0;
|
||||
softwareRenderer->currentWx = 0;
|
||||
|
||||
if (softwareRenderer->sgbTransfer == 1) {
|
||||
size_t offset = 2 * ((y & 7) + (y >> 3) * GB_VIDEO_HORIZONTAL_PIXELS);
|
||||
if (offset >= 0x1000) {
|
||||
|
@ -702,7 +712,9 @@ static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer)
|
|||
}
|
||||
}
|
||||
softwareRenderer->lastY = GB_VIDEO_VERTICAL_PIXELS;
|
||||
softwareRenderer->lastX = 0;
|
||||
softwareRenderer->currentWy = 0;
|
||||
softwareRenderer->currentWx = 0;
|
||||
softwareRenderer->hasWindow = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -224,7 +224,6 @@ void _endMode0(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
|||
++video->ly;
|
||||
video->p->memory.io[REG_LY] = video->ly;
|
||||
GBRegisterSTAT oldStat = video->stat;
|
||||
video->stat = GBRegisterSTATSetLYC(video->stat, lyc == video->ly);
|
||||
if (video->ly < GB_VIDEO_VERTICAL_PIXELS) {
|
||||
next = GB_VIDEO_MODE_2_LENGTH;
|
||||
video->mode = 2;
|
||||
|
@ -246,6 +245,14 @@ void _endMode0(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
|||
if (!_statIRQAsserted(video, oldStat) && _statIRQAsserted(video, video->stat)) {
|
||||
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT);
|
||||
}
|
||||
|
||||
// LYC stat is delayed 1 T-cycle
|
||||
oldStat = video->stat;
|
||||
video->stat = GBRegisterSTATSetLYC(video->stat, lyc == video->ly);
|
||||
if (!_statIRQAsserted(video, oldStat) && _statIRQAsserted(video, video->stat)) {
|
||||
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT);
|
||||
}
|
||||
|
||||
GBUpdateIRQs(video->p);
|
||||
video->p->memory.io[REG_STAT] = video->stat;
|
||||
mTimingSchedule(timing, &video->modeEvent, (next << video->p->doubleSpeed) - cyclesLate);
|
||||
|
|
|
@ -548,16 +548,16 @@ void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) {
|
|||
break;
|
||||
case REG_IE:
|
||||
gba->memory.io[REG_IE >> 1] = value;
|
||||
GBATestIRQ(gba->cpu, 1);
|
||||
GBATestIRQ(gba, 1);
|
||||
return;
|
||||
case REG_IF:
|
||||
value = gba->memory.io[REG_IF >> 1] & ~value;
|
||||
gba->memory.io[REG_IF >> 1] = value;
|
||||
GBATestIRQ(gba->cpu, 1);
|
||||
GBATestIRQ(gba, 1);
|
||||
return;
|
||||
case REG_IME:
|
||||
gba->memory.io[REG_IME >> 1] = value;
|
||||
GBATestIRQ(gba->cpu, 1);
|
||||
GBATestIRQ(gba, 1);
|
||||
return;
|
||||
case REG_MAX:
|
||||
// Some bad interrupt libraries will write to this
|
||||
|
|
|
@ -74,7 +74,7 @@ static inline uint16_t _printLine(struct CLIDebugger* debugger, uint16_t address
|
|||
};
|
||||
disPtr[0] = '\t';
|
||||
++disPtr;
|
||||
LR35902Disassemble(&info, disPtr, sizeof(disassembly) - (disPtr - disassembly));
|
||||
LR35902Disassemble(&info, address, disPtr, sizeof(disassembly) - (disPtr - disassembly));
|
||||
be->printf(be, "%s\n", disassembly);
|
||||
return address;
|
||||
}
|
||||
|
@ -87,6 +87,7 @@ static void _printStatus(struct CLIDebuggerSystem* debugger) {
|
|||
be->printf(be, "D: %02X E: %02X (DE: %04X)\n", cpu->d, cpu->e, cpu->de);
|
||||
be->printf(be, "H: %02X L: %02X (HL: %04X)\n", cpu->h, cpu->l, cpu->hl);
|
||||
be->printf(be, "PC: %04X SP: %04X\n", cpu->pc, cpu->sp);
|
||||
_printFlags(be, cpu->f);
|
||||
|
||||
struct LR35902Debugger* platDebugger = (struct LR35902Debugger*) debugger->p->d.platform;
|
||||
size_t i;
|
||||
|
@ -96,7 +97,9 @@ static void _printStatus(struct CLIDebuggerSystem* debugger) {
|
|||
if (i) {
|
||||
be->printf(be, "\n");
|
||||
}
|
||||
_printFlags(be, cpu->f);
|
||||
if (platDebugger->printStatus) {
|
||||
platDebugger->printStatus(debugger);
|
||||
}
|
||||
_printLine(debugger->p, cpu->pc, cpu->memory.currentSegment(cpu, cpu->pc));
|
||||
}
|
||||
|
||||
|
|
|
@ -75,21 +75,22 @@ static bool LR35902DebuggerGetRegister(struct mDebuggerPlatform*, const char* na
|
|||
static bool LR35902DebuggerSetRegister(struct mDebuggerPlatform*, const char* name, int32_t value);
|
||||
|
||||
struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void) {
|
||||
struct mDebuggerPlatform* platform = (struct mDebuggerPlatform*) malloc(sizeof(struct LR35902Debugger));
|
||||
platform->entered = LR35902DebuggerEnter;
|
||||
platform->init = LR35902DebuggerInit;
|
||||
platform->deinit = LR35902DebuggerDeinit;
|
||||
platform->setBreakpoint = LR35902DebuggerSetBreakpoint;
|
||||
platform->listBreakpoints = LR35902DebuggerListBreakpoints;
|
||||
platform->clearBreakpoint = LR35902DebuggerClearBreakpoint;
|
||||
platform->setWatchpoint = LR35902DebuggerSetWatchpoint;
|
||||
platform->listWatchpoints = LR35902DebuggerListWatchpoints;
|
||||
platform->checkBreakpoints = LR35902DebuggerCheckBreakpoints;
|
||||
platform->hasBreakpoints = LR35902DebuggerHasBreakpoints;
|
||||
platform->trace = LR35902DebuggerTrace;
|
||||
platform->getRegister = LR35902DebuggerGetRegister;
|
||||
platform->setRegister = LR35902DebuggerSetRegister;
|
||||
return platform;
|
||||
struct LR35902Debugger* platform = malloc(sizeof(struct LR35902Debugger));
|
||||
platform->d.entered = LR35902DebuggerEnter;
|
||||
platform->d.init = LR35902DebuggerInit;
|
||||
platform->d.deinit = LR35902DebuggerDeinit;
|
||||
platform->d.setBreakpoint = LR35902DebuggerSetBreakpoint;
|
||||
platform->d.listBreakpoints = LR35902DebuggerListBreakpoints;
|
||||
platform->d.clearBreakpoint = LR35902DebuggerClearBreakpoint;
|
||||
platform->d.setWatchpoint = LR35902DebuggerSetWatchpoint;
|
||||
platform->d.listWatchpoints = LR35902DebuggerListWatchpoints;
|
||||
platform->d.checkBreakpoints = LR35902DebuggerCheckBreakpoints;
|
||||
platform->d.hasBreakpoints = LR35902DebuggerHasBreakpoints;
|
||||
platform->d.trace = LR35902DebuggerTrace;
|
||||
platform->d.getRegister = LR35902DebuggerGetRegister;
|
||||
platform->d.setRegister = LR35902DebuggerSetRegister;
|
||||
platform->printStatus = NULL;
|
||||
return &platform->d;
|
||||
}
|
||||
|
||||
void LR35902DebuggerInit(void* cpu, struct mDebuggerPlatform* platform) {
|
||||
|
@ -215,7 +216,7 @@ static void LR35902DebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t*
|
|||
disPtr[0] = ':';
|
||||
disPtr[1] = ' ';
|
||||
disPtr += 2;
|
||||
LR35902Disassemble(&info, disPtr, sizeof(disassembly) - (disPtr - disassembly));
|
||||
LR35902Disassemble(&info, address, disPtr, sizeof(disassembly) - (disPtr - disassembly));
|
||||
|
||||
*length = snprintf(out, *length, "A: %02X F: %02X B: %02X C: %02X D: %02X E: %02X H: %02X L: %02X SP: %04X PC: %02X:%04X | %s",
|
||||
cpu->a, cpu->f.packed, cpu->b, cpu->c,
|
||||
|
|
|
@ -199,6 +199,7 @@ DEFINE_DECODER_LR35902(ADDSP, info->mnemonic = LR35902_MN_ADD; \
|
|||
DEFINE_DECODER_LR35902(JR ## CONDITION_NAME, \
|
||||
info->mnemonic = LR35902_MN_JR; \
|
||||
info->condition = CONDITION; \
|
||||
info->op1.flags = LR35902_OP_FLAG_RELATIVE; \
|
||||
return 1;)
|
||||
|
||||
#define DEFINE_CALL_INSTRUCTION_LR35902(CONDITION_NAME, CONDITION) \
|
||||
|
@ -314,15 +315,21 @@ DEFINE_POPPUSH_DECODER_LR35902(DE);
|
|||
DEFINE_POPPUSH_DECODER_LR35902(HL);
|
||||
DEFINE_POPPUSH_DECODER_LR35902(AF);
|
||||
|
||||
#define DEFINE_CB_OP_DECODER_LR35902(NAME, BODY, OP) \
|
||||
DEFINE_DECODER_LR35902(NAME ## B, info->OP.reg = LR35902_REG_B; BODY) \
|
||||
DEFINE_DECODER_LR35902(NAME ## C, info->OP.reg = LR35902_REG_C; BODY) \
|
||||
DEFINE_DECODER_LR35902(NAME ## D, info->OP.reg = LR35902_REG_D; BODY) \
|
||||
DEFINE_DECODER_LR35902(NAME ## E, info->OP.reg = LR35902_REG_E; BODY) \
|
||||
DEFINE_DECODER_LR35902(NAME ## H, info->OP.reg = LR35902_REG_H; BODY) \
|
||||
DEFINE_DECODER_LR35902(NAME ## L, info->OP.reg = LR35902_REG_L; BODY) \
|
||||
DEFINE_DECODER_LR35902(NAME ## HL, info->OP.reg = LR35902_REG_HL; info->OP.flags = LR35902_OP_FLAG_MEMORY; BODY) \
|
||||
DEFINE_DECODER_LR35902(NAME ## A, info->OP.reg = LR35902_REG_A; BODY)
|
||||
|
||||
#define DEFINE_CB_2_DECODER_LR35902(NAME, BODY) \
|
||||
DEFINE_DECODER_LR35902(NAME ## B, info->op2.reg = LR35902_REG_B; BODY) \
|
||||
DEFINE_DECODER_LR35902(NAME ## C, info->op2.reg = LR35902_REG_C; BODY) \
|
||||
DEFINE_DECODER_LR35902(NAME ## D, info->op2.reg = LR35902_REG_D; BODY) \
|
||||
DEFINE_DECODER_LR35902(NAME ## E, info->op2.reg = LR35902_REG_E; BODY) \
|
||||
DEFINE_DECODER_LR35902(NAME ## H, info->op2.reg = LR35902_REG_H; BODY) \
|
||||
DEFINE_DECODER_LR35902(NAME ## L, info->op2.reg = LR35902_REG_L; BODY) \
|
||||
DEFINE_DECODER_LR35902(NAME ## HL, info->op2.reg = LR35902_REG_HL; info->op2.flags = LR35902_OP_FLAG_MEMORY; BODY) \
|
||||
DEFINE_DECODER_LR35902(NAME ## A, info->op2.reg = LR35902_REG_A; BODY)
|
||||
DEFINE_CB_OP_DECODER_LR35902(NAME, BODY, op2)
|
||||
|
||||
#define DEFINE_CB_1_DECODER_LR35902(NAME, BODY) \
|
||||
DEFINE_CB_OP_DECODER_LR35902(NAME, BODY, op1)
|
||||
|
||||
#define DEFINE_CB_DECODER_LR35902(NAME, BODY) \
|
||||
DEFINE_CB_2_DECODER_LR35902(NAME ## 0, info->op1.immediate = 0; BODY) \
|
||||
|
@ -339,17 +346,19 @@ DEFINE_CB_DECODER_LR35902(RES, info->mnemonic = LR35902_MN_RES)
|
|||
DEFINE_CB_DECODER_LR35902(SET, info->mnemonic = LR35902_MN_SET)
|
||||
|
||||
#define DEFINE_CB_X_DECODER_LR35902(NAME) \
|
||||
DEFINE_CB_2_DECODER_LR35902(NAME, info->mnemonic = LR35902_MN_ ## NAME) \
|
||||
DEFINE_DECODER_LR35902(NAME ## A_, info->mnemonic = LR35902_MN_ ## NAME; info->op1.reg = LR35902_REG_A)
|
||||
DEFINE_CB_1_DECODER_LR35902(NAME, info->mnemonic = LR35902_MN_ ## NAME) \
|
||||
DEFINE_DECODER_LR35902(NAME ## A_, info->mnemonic = LR35902_MN_ ## NAME; \
|
||||
info->op1.flags = LR35902_OP_FLAG_IMPLICIT; \
|
||||
info->op1.reg = LR35902_REG_A;)
|
||||
|
||||
DEFINE_CB_X_DECODER_LR35902(RL)
|
||||
DEFINE_CB_X_DECODER_LR35902(RLC)
|
||||
DEFINE_CB_X_DECODER_LR35902(RR)
|
||||
DEFINE_CB_X_DECODER_LR35902(RRC)
|
||||
DEFINE_CB_2_DECODER_LR35902(SLA, info->mnemonic = LR35902_MN_SLA)
|
||||
DEFINE_CB_2_DECODER_LR35902(SRA, info->mnemonic = LR35902_MN_SRA)
|
||||
DEFINE_CB_2_DECODER_LR35902(SRL, info->mnemonic = LR35902_MN_SRL)
|
||||
DEFINE_CB_2_DECODER_LR35902(SWAP, info->mnemonic = LR35902_MN_SWAP)
|
||||
DEFINE_CB_1_DECODER_LR35902(SLA, info->mnemonic = LR35902_MN_SLA)
|
||||
DEFINE_CB_1_DECODER_LR35902(SRA, info->mnemonic = LR35902_MN_SRA)
|
||||
DEFINE_CB_1_DECODER_LR35902(SRL, info->mnemonic = LR35902_MN_SRL)
|
||||
DEFINE_CB_1_DECODER_LR35902(SWAP, info->mnemonic = LR35902_MN_SWAP)
|
||||
|
||||
DEFINE_DECODER_LR35902(DI, info->mnemonic = LR35902_MN_DI)
|
||||
DEFINE_DECODER_LR35902(EI, info->mnemonic = LR35902_MN_EI)
|
||||
|
@ -489,7 +498,7 @@ static const char* _lr35902MnemonicStrings[] = {
|
|||
};
|
||||
|
||||
|
||||
static int _decodeOperand(struct LR35902Operand op, char* buffer, int blen) {
|
||||
static int _decodeOperand(struct LR35902Operand op, uint16_t pc, char* buffer, int blen) {
|
||||
int total = 0;
|
||||
if (op.flags & LR35902_OP_FLAG_IMPLICIT) {
|
||||
return 0;
|
||||
|
@ -503,7 +512,12 @@ static int _decodeOperand(struct LR35902Operand op, char* buffer, int blen) {
|
|||
int written = snprintf(buffer, blen - 1, "%s", _lr35902Registers[op.reg]);
|
||||
ADVANCE(written);
|
||||
} else {
|
||||
int written = snprintf(buffer, blen - 1, "$%02X", op.immediate);
|
||||
int written;
|
||||
if (op.flags & LR35902_OP_FLAG_RELATIVE) {
|
||||
written = snprintf(buffer, blen - 1, "$%04X", pc + (int8_t) op.immediate);
|
||||
} else {
|
||||
written = snprintf(buffer, blen - 1, "$%02X", op.immediate);
|
||||
}
|
||||
ADVANCE(written);
|
||||
if (op.reg) {
|
||||
strncpy(buffer, "+", blen - 1);
|
||||
|
@ -525,7 +539,7 @@ static int _decodeOperand(struct LR35902Operand op, char* buffer, int blen) {
|
|||
return total;
|
||||
}
|
||||
|
||||
int LR35902Disassemble(struct LR35902InstructionInfo* info, char* buffer, int blen) {
|
||||
int LR35902Disassemble(struct LR35902InstructionInfo* info, uint16_t pc, char* buffer, int blen) {
|
||||
const char* mnemonic = _lr35902MnemonicStrings[info->mnemonic];
|
||||
int written;
|
||||
int total = 0;
|
||||
|
@ -545,7 +559,7 @@ int LR35902Disassemble(struct LR35902InstructionInfo* info, char* buffer, int bl
|
|||
}
|
||||
|
||||
if (info->op1.reg || info->op1.immediate || info->op2.reg || info->op2.immediate) {
|
||||
written = _decodeOperand(info->op1, buffer, blen);
|
||||
written = _decodeOperand(info->op1, pc, buffer, blen);
|
||||
ADVANCE(written);
|
||||
}
|
||||
|
||||
|
@ -554,7 +568,7 @@ int LR35902Disassemble(struct LR35902InstructionInfo* info, char* buffer, int bl
|
|||
strncpy(buffer, ", ", blen - 1);
|
||||
ADVANCE(2);
|
||||
}
|
||||
written = _decodeOperand(info->op2, buffer, blen);
|
||||
written = _decodeOperand(info->op2, pc, buffer, blen);
|
||||
ADVANCE(written);
|
||||
}
|
||||
|
||||
|
|
|
@ -85,5 +85,7 @@ void AbstractUpdater::updateDownloaded(QNetworkReply* reply) {
|
|||
}
|
||||
f.write(bytes);
|
||||
}
|
||||
f.flush();
|
||||
f.close();
|
||||
emit updateDone(true);
|
||||
}
|
||||
|
|
|
@ -183,7 +183,7 @@ if(Qt5Multimedia_FOUND)
|
|||
list(APPEND SOURCE_FILES
|
||||
VideoDumper.cpp)
|
||||
if (WIN32 AND QT_STATIC)
|
||||
list(APPEND QT_LIBRARIES Qt5::QWindowsAudioPlugin Qt5::DSServicePlugin
|
||||
list(APPEND QT_LIBRARIES Qt5::QWindowsAudioPlugin Qt5::DSServicePlugin Qt5::QWindowsVistaStylePlugin
|
||||
strmiids mfuuid mfplat mf ksguid dxva2 evr d3d9)
|
||||
endif()
|
||||
list(APPEND QT_LIBRARIES Qt5::Multimedia)
|
||||
|
@ -287,15 +287,15 @@ endif()
|
|||
if(QT_STATIC)
|
||||
find_library(QTPCRE NAMES qtpcre2 qtpcre)
|
||||
if(WIN32)
|
||||
list(APPEND QT_LIBRARIES qwindows dwmapi imm32 uxtheme Qt5EventDispatcherSupport Qt5FontDatabaseSupport Qt5ThemeSupport)
|
||||
set_target_properties(Qt5::Core PROPERTIES INTERFACE_LINK_LIBRARIES "${QTPCRE};version;winmm;ws2_32")
|
||||
list(APPEND QT_LIBRARIES qwindows dwmapi imm32 uxtheme Qt5EventDispatcherSupport Qt5FontDatabaseSupport Qt5ThemeSupport Qt5WindowsUIAutomationSupport)
|
||||
set_target_properties(Qt5::Core PROPERTIES INTERFACE_LINK_LIBRARIES "${QTPCRE};version;winmm;ssl;crypto;ws2_32;iphlpapi;crypt32;userenv;netapi32;wtsapi32")
|
||||
elseif(APPLE)
|
||||
find_package(Cups)
|
||||
find_package(Qt5PrintSupport)
|
||||
find_library(QTFREETYPE NAMES qtfreetype)
|
||||
find_library(QTHARFBUZZ NAMES qtharfbuzzng qtharfbuzz)
|
||||
find_library(QTPLATFORMSUPPORT NAMES Qt5PlatformSupport)
|
||||
list(APPEND QT_LIBRARIES Cups Qt5::PrintSupport Qt5::QCocoaIntegrationPlugin Qt5::CoreAudioPlugin Qt5::AVFServicePlugin Qt5::QCocoaPrinterSupportPlugin ${QTPLATFORMSUPPORT} "-framework AVFoundation" "-framework CoreMedia")
|
||||
list(APPEND QT_LIBRARIES Cups Qt5::PrintSupport Qt5::QCocoaIntegrationPlugin Qt5::CoreAudioPlugin Qt5::AVFServicePlugin Qt5::QCocoaPrinterSupportPlugin ${QTPLATFORMSUPPORT} "-framework AVFoundation" "-framework CoreMedia" "-framework SystemConfiguration" "-framework Security")
|
||||
set_target_properties(Qt5::Core PROPERTIES INTERFACE_LINK_LIBRARIES "${QTPCRE};${QTHARFBUZZ};${QTFREETYPE}")
|
||||
link_directories()
|
||||
endif()
|
||||
|
|
|
@ -49,7 +49,7 @@ CoreController* CoreManager::loadGame(const QString& path) {
|
|||
vf = vfclone;
|
||||
}
|
||||
dir->close(dir);
|
||||
loadGame(vf, fname, base);
|
||||
return loadGame(vf, fname, base);
|
||||
} else {
|
||||
LOG(QT, ERROR) << tr("Failed to open game file: %1").arg(path);
|
||||
}
|
||||
|
|
|
@ -23,14 +23,18 @@ bool VideoDumper::present(const QVideoFrame& frame) {
|
|||
QImage::Format format = QVideoFrame::imageFormatFromPixelFormat(vFormat);
|
||||
bool swap = false;
|
||||
if (format == QImage::Format_Invalid) {
|
||||
vFormat = static_cast<QVideoFrame::PixelFormat>(vFormat - QVideoFrame::Format_BGRA32 + QVideoFrame::Format_ARGB32);
|
||||
format = QVideoFrame::imageFormatFromPixelFormat(vFormat);
|
||||
if (format == QImage::Format_ARGB32) {
|
||||
format = QImage::Format_RGBA8888;
|
||||
} else if (format == QImage::Format_ARGB32_Premultiplied) {
|
||||
format = QImage::Format_RGBA8888_Premultiplied;
|
||||
if (vFormat < QVideoFrame::Format_BGRA5658_Premultiplied) {
|
||||
vFormat = static_cast<QVideoFrame::PixelFormat>(vFormat - QVideoFrame::Format_BGRA32 + QVideoFrame::Format_ARGB32);
|
||||
format = QVideoFrame::imageFormatFromPixelFormat(vFormat);
|
||||
if (format == QImage::Format_ARGB32) {
|
||||
format = QImage::Format_RGBA8888;
|
||||
} else if (format == QImage::Format_ARGB32_Premultiplied) {
|
||||
format = QImage::Format_RGBA8888_Premultiplied;
|
||||
}
|
||||
swap = true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
swap = true;
|
||||
}
|
||||
uchar* bits = mappedFrame.bits();
|
||||
QImage image(bits, mappedFrame.width(), mappedFrame.height(), mappedFrame.bytesPerLine(), format);
|
||||
|
|
|
@ -269,6 +269,11 @@
|
|||
<string>HEVC</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>HEVC (NVENC)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>VP8</string>
|
||||
|
|
|
@ -1253,7 +1253,7 @@ void Window::setupMenu(QMenuBar* menubar) {
|
|||
fileMenu->addSeparator();
|
||||
#endif
|
||||
|
||||
QAction* about = new QAction(tr("About"), fileMenu);
|
||||
QAction* about = new QAction(tr("About..."), fileMenu);
|
||||
connect(about, &QAction::triggered, openTView<AboutScreen>());
|
||||
fileMenu->addAction(about);
|
||||
|
||||
|
|
|
@ -994,12 +994,23 @@ void InputController::setupCam() {
|
|||
#ifdef BUILD_QT_MULTIMEDIA
|
||||
if (!m_camera) {
|
||||
m_camera = std::make_unique<QCamera>();
|
||||
connect(m_camera.get(), &QCamera::statusChanged, this, &InputController::prepareCamSettings);
|
||||
}
|
||||
QVideoFrame::PixelFormat format(QVideoFrame::Format_RGB32);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
|
||||
m_camera->setCaptureMode(QCamera::CaptureVideo);
|
||||
m_camera->setViewfinder(&m_videoDumper);
|
||||
m_camera->load();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef BUILD_QT_MULTIMEDIA
|
||||
void InputController::prepareCamSettings(QCamera::Status status) {
|
||||
if (status != QCamera::LoadedStatus || m_camera->state() == QCamera::ActiveState) {
|
||||
return;
|
||||
}
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
|
||||
QVideoFrame::PixelFormat format(QVideoFrame::Format_RGB32);
|
||||
QCameraViewfinderSettings settings;
|
||||
QSize size(1920, 1080);
|
||||
QSize size(1280, 720);
|
||||
auto cameraRes = m_camera->supportedViewfinderResolutions(settings);
|
||||
for (auto& cameraSize : cameraRes) {
|
||||
if (cameraSize.width() < m_image.w || cameraSize.height() < m_image.h) {
|
||||
|
@ -1010,10 +1021,11 @@ void InputController::setupCam() {
|
|||
}
|
||||
}
|
||||
settings.setResolution(size);
|
||||
|
||||
auto cameraFormats = m_camera->supportedViewfinderPixelFormats(settings);
|
||||
auto goodFormats = m_videoDumper.supportedPixelFormats();
|
||||
bool goodFormatFound = false;
|
||||
for (auto& goodFormat : goodFormats) {
|
||||
for (const auto& goodFormat : goodFormats) {
|
||||
if (cameraFormats.contains(goodFormat)) {
|
||||
settings.setPixelFormat(goodFormat);
|
||||
format = goodFormat;
|
||||
|
@ -1023,20 +1035,20 @@ void InputController::setupCam() {
|
|||
}
|
||||
if (!goodFormatFound) {
|
||||
LOG(QT, WARN) << "Could not find a valid camera format!";
|
||||
for (const auto& format : cameraFormats) {
|
||||
LOG(QT, WARN) << "Camera supported format: " << QString::number(format);
|
||||
}
|
||||
}
|
||||
m_camera->setViewfinderSettings(settings);
|
||||
#endif
|
||||
m_camera->setCaptureMode(QCamera::CaptureVideo);
|
||||
m_camera->setViewfinder(&m_videoDumper);
|
||||
m_camera->start();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void InputController::teardownCam() {
|
||||
#ifdef BUILD_QT_MULTIMEDIA
|
||||
if (m_camera) {
|
||||
m_camera->stop();
|
||||
m_camera.reset();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#ifdef BUILD_QT_MULTIMEDIA
|
||||
#include "VideoDumper.h"
|
||||
#include <QCamera>
|
||||
#endif
|
||||
|
||||
struct mRotationSource;
|
||||
|
@ -144,6 +145,9 @@ protected:
|
|||
bool eventFilter(QObject*, QEvent*) override;
|
||||
|
||||
private slots:
|
||||
#ifdef BUILD_QT_MULTIMEDIA
|
||||
void prepareCamSettings(QCamera::Status);
|
||||
#endif
|
||||
void setupCam();
|
||||
void teardownCam();
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <QtPlugin>
|
||||
#ifdef Q_OS_WIN
|
||||
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
|
||||
Q_IMPORT_PLUGIN(QWindowsVistaStylePlugin);
|
||||
#ifdef BUILD_QT_MULTIMEDIA
|
||||
Q_IMPORT_PLUGIN(QWindowsAudioPlugin);
|
||||
Q_IMPORT_PLUGIN(DSServicePlugin);
|
||||
|
|
Loading…
Reference in New Issue