Skip to content

Commit 6aa9f2e

Browse files
committed
fpgx35: work around GDI bug
GDI ExtFloodFill tries to convert a device specific bitmap to a normal bitmap for speed. Prior to NT 4 this function has a bug, and so it will delete the device surface, which causes crashes and thus bugcheck (as it brings down csrss). Do some pattern matching in DrvCopyBits and make it fail if it's being called by this conversion function. This causes a fallback to using the device specific bitmap, which is what is wanted. Fixes bugcheck under NT 3.51 when running (at least) VC4 IDE.
1 parent b3ddb91 commit 6aa9f2e

File tree

2 files changed

+818
-1
lines changed

2 files changed

+818
-1
lines changed

fpgx35dll/source/draw.c

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "driver.h"
22
#include "runtime.h"
3+
#include "ppcinst.h"
34

45
#define POINTER_SWAP32(ptr) (PULONG)(_Mmio_MungeAddressForBig(ptr, sizeof(ULONG)))
56

@@ -173,6 +174,61 @@ BOOL copyFromFb)
173174
return TRUE;
174175
}
175176

177+
static inline LONG HookSignExtBranch(LONG x) {
178+
return x & 0x2000000 ? (LONG)(x | 0xFC000000) : (LONG)(x);
179+
}
180+
181+
static inline LONG HookSignExt16(SHORT x) {
182+
return (LONG)x;
183+
}
184+
185+
static BOOL IsRetAddrBad(PPPC_INSTRUCTION Addr) {
186+
static ULONG s_RetAddrBad = 0;
187+
if (s_RetAddrBad != 0) return (ULONG)Addr == s_RetAddrBad;
188+
PPPC_INSTRUCTION Insn = Addr;
189+
// Two instructions afterwards is beq+ ?
190+
Insn += 2;
191+
if (Insn->Primary_Op != BC_OP) return FALSE;
192+
if (Insn->Bform_BO != 0xD) return FALSE;
193+
Insn++;
194+
// Next bl (within next 5 instructions) leads to "lwz r3, x(r2)" insn (or a wrapper for that)
195+
PPPC_INSTRUCTION Bl = NULL;
196+
for (int i = 0; i < 5; i++, Insn++) {
197+
if (Insn->Primary_Op != B_OP) continue;
198+
if (Insn->Iform_LK == 0) continue;
199+
Bl = Insn;
200+
break;
201+
}
202+
203+
if (Bl == NULL) return FALSE;
204+
205+
Insn = (PPPC_INSTRUCTION)((ULONG)Bl + HookSignExtBranch(Bl->Iform_LI << 2));
206+
if (Insn->Primary_Op == LWZ_OP && Insn->Dform_RA == 2 && Insn->Dform_RT == 3) {
207+
// looks good...
208+
s_RetAddrBad = (ULONG)Addr;
209+
return TRUE;
210+
}
211+
212+
// might be wrapping it, bl is within 16 instructions
213+
Bl = NULL;
214+
for (int i = 0; i < 16; i++, Insn++) {
215+
if (Insn->Long == 0x4E800020) break; // blr
216+
if (Insn->Primary_Op != B_OP) continue;
217+
if (Insn->Iform_LK == 0) continue;
218+
Bl = Insn;
219+
break;
220+
}
221+
if (Bl == NULL) return FALSE;
222+
Insn = (PPPC_INSTRUCTION)((ULONG)Bl + HookSignExtBranch(Bl->Iform_LI << 2));
223+
if (Insn->Primary_Op == LWZ_OP && Insn->Dform_RA == 2 && Insn->Dform_RT == 3) {
224+
// looks good...
225+
s_RetAddrBad = (ULONG)Addr;
226+
return TRUE;
227+
}
228+
229+
return FALSE;
230+
}
231+
176232
BOOL DrvCopyBits(
177233
SURFOBJ *psoDest,
178234
SURFOBJ *psoSrc,
@@ -199,7 +255,7 @@ POINTL *pptlSrc)
199255
to this function as a result of the following GDI functions:
200256
SetDIBits, SetDIBitsToDevice, GetDIBits, SetBitmapBits, and GetBitmapBits.
201257
*/
202-
258+
203259
// If both surfaces are not device managed, just call original func:
204260
if (psoDest->iType != STYPE_DEVBITMAP && psoSrc->iType != STYPE_DEVBITMAP) {
205261
return EngCopyBits(psoDest, psoSrc, pco, pxlo, prclDest, pptlSrc);
@@ -229,6 +285,15 @@ POINTL *pptlSrc)
229285
return CopyBitsSwap32(psoDest, psoSrc, NULL, NULL, prclDest, &point, FALSE);
230286
}
231287

288+
// Try to detect CvtDFB2DIB, and fail if so.
289+
// On NT 3.5x, success in that scenario causes the caller to delete the source.
290+
// If that source is our device-managed surface, this CANNOT happen!
291+
if (psoSrc->iType == STYPE_DEVBITMAP && psoDest->iType == STYPE_BITMAP) {
292+
// Get the return address of function
293+
PPPC_INSTRUCTION Insn = (PPPC_INSTRUCTION)__builtin_return_address(0);
294+
if (IsRetAddrBad(Insn)) return FALSE;
295+
}
296+
232297
// Copying to framebuffer
233298
if (psoDest->iType == STYPE_DEVBITMAP) {
234299
// Source is always going to be a 32bpp bitmap

0 commit comments

Comments
 (0)