void JitILBase::lXz(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITLoadStoreOff); FALLBACK_IF(js.memcheck); IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); if (inst.RA) addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); if (inst.OPCD & 1) ibuild.EmitStoreGReg(addr, inst.RA); IREmitter::InstLoc val; switch (inst.OPCD & ~0x1) { case 32: val = ibuild.EmitLoad32(addr); break; //lwz case 40: val = ibuild.EmitLoad16(addr); break; //lhz case 34: val = ibuild.EmitLoad8(addr); break; //lbz default: PanicAlert("lXz: invalid access size"); val = nullptr; break; } ibuild.EmitStoreGReg(val, inst.RD); }
void JitILBase::stX(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITLoadStoreOff); FALLBACK_IF(js.memcheck); IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); IREmitter::InstLoc value = ibuild.EmitLoadGReg(inst.RS); if (inst.RA) addr = ibuild.EmitAdd(ibuild.EmitLoadGReg(inst.RA), addr); if (inst.OPCD & 1) ibuild.EmitStoreGReg(addr, inst.RA); switch (inst.OPCD & ~1) { case 36: ibuild.EmitStore32(value, addr); break; //stw case 44: ibuild.EmitStore16(value, addr); break; //sth case 38: ibuild.EmitStore8(value, addr); break; //stb default: _assert_msg_(DYNA_REC, 0, "AWETKLJASDLKF"); return; } }
void JitILBase::stXx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITLoadStoreOff); FALLBACK_IF(js.memcheck); IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB); IREmitter::InstLoc value = ibuild.EmitLoadGReg(inst.RS); addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); if (inst.SUBOP10 & 32) ibuild.EmitStoreGReg(addr, inst.RA); switch (inst.SUBOP10 & ~32) { case 151: ibuild.EmitStore32(value, addr); break; //stw case 407: ibuild.EmitStore16(value, addr); break; //sth case 215: ibuild.EmitStore8(value, addr); break; //stb default: _assert_msg_(DYNA_REC, 0, "AWETKLJASDLKF"); return; } }
void Jit64::lfs(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITLoadStoreFloatingOff); int d = inst.RD; int a = inst.RA; FALLBACK_IF(!a); s32 offset = (s32)(s16)inst.SIMM_16; SafeLoadToReg(EAX, gpr.R(a), 32, offset, RegistersInUse(), false); MEMCHECK_START fpr.Lock(d); fpr.BindToRegister(d, false); ConvertSingleToDouble(fpr.RX(d), EAX, true); MEMCHECK_END fpr.UnlockAll(); }
void JitArm::ps_sel(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; ARMReg vA0 = fpr.R0(a); ARMReg vA1 = fpr.R1(a); ARMReg vB0 = fpr.R0(b); ARMReg vB1 = fpr.R1(b); ARMReg vC0 = fpr.R0(c); ARMReg vC1 = fpr.R1(c); ARMReg vD0 = fpr.R0(d, false); ARMReg vD1 = fpr.R1(d, false); VCMP(vA0); VMRS(_PC); FixupBranch GT0 = B_CC(CC_GE); VMOV(vD0, vB0); FixupBranch EQ0 = B(); SetJumpTarget(GT0); VMOV(vD0, vC0); SetJumpTarget(EQ0); VCMP(vA1); VMRS(_PC); FixupBranch GT1 = B_CC(CC_GE); VMOV(vD1, vB1); FixupBranch EQ1 = B(); SetJumpTarget(GT1); VMOV(vD1, vC1); SetJumpTarget(EQ1); }
// Zero cache line. void JitILBase::dcbz(UGeckoInstruction inst) { FALLBACK_IF(true); // TODO! #if 0 if (Core::g_CoreStartupParameter.bJITOff || Core::g_CoreStartupParameter.bJITLoadStoreOff) {Default(inst); return;} // turn off from debugger INSTRUCTION_START; MOV(32, R(EAX), gpr.R(inst.RB)); if (inst.RA) ADD(32, R(EAX), gpr.R(inst.RA)); AND(32, R(EAX), Imm32(~31)); PXOR(XMM0, R(XMM0)); #if _M_X86_64 MOVAPS(MComplex(EBX, EAX, SCALE_1, 0), XMM0); MOVAPS(MComplex(EBX, EAX, SCALE_1, 16), XMM0); #else AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK)); MOVAPS(MDisp(EAX, (u32)Memory::base), XMM0); MOVAPS(MDisp(EAX, (u32)Memory::base + 16), XMM0); #endif #endif }
void JitArm64::mfspr(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITSystemRegistersOff); u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F); int d = inst.RD; switch (iIndex) { case SPR_TL: case SPR_TU: { ARM64Reg WA = gpr.GetReg(); ARM64Reg WB = gpr.GetReg(); ARM64Reg XA = EncodeRegTo64(WA); ARM64Reg XB = EncodeRegTo64(WB); // An inline implementation of CoreTiming::GetFakeTimeBase, since in timer-heavy games the // cost of calling out to C for this is actually significant. MOVI2R(XA, (u64)&CoreTiming::globalTimer); LDR(INDEX_UNSIGNED, XA, XA, 0); MOVI2R(XB, (u64)&CoreTiming::fakeTBStartTicks); LDR(INDEX_UNSIGNED, XB, XB, 0); SUB(XA, XA, XB); // It might seem convenient to correct the timer for the block position here for even more accurate // timing, but as of currently, this can break games. If we end up reading a time *after* the time // at which an interrupt was supposed to occur, e.g. because we're 100 cycles into a block with only // 50 downcount remaining, some games don't function correctly, such as Karaoke Party Revolution, // which won't get past the loading screen. // a / 12 = (a * 0xAAAAAAAAAAAAAAAB) >> 67 ORR(XB, SP, 1, 60); ADD(XB, XB, 1); UMULH(XA, XA, XB); MOVI2R(XB, (u64)&CoreTiming::fakeTBStartValue); LDR(INDEX_UNSIGNED, XB, XB, 0); ADD(XA, XB, XA, ArithOption(XA, ST_LSR, 3)); STR(INDEX_UNSIGNED, XA, X29, PPCSTATE_OFF(spr[SPR_TL])); if (MergeAllowedNextInstructions(1)) { const UGeckoInstruction& next = js.op[1].inst; // Two calls of TU/TL next to each other are extremely common in typical usage, so merge them // if we can. u32 nextIndex = (next.SPRU << 5) | (next.SPRL & 0x1F); // Be careful; the actual opcode is for mftb (371), not mfspr (339) int n = next.RD; if (next.OPCD == 31 && next.SUBOP10 == 371 && (nextIndex == SPR_TU || nextIndex == SPR_TL) && n != d) { js.downcountAmount++; js.skipInstructions = 1; gpr.BindToRegister(d, false); gpr.BindToRegister(n, false); if (iIndex == SPR_TL) MOV(gpr.R(d), WA); else ORR(EncodeRegTo64(gpr.R(d)), SP, XA, ArithOption(XA, ST_LSR, 32)); if (nextIndex == SPR_TL) MOV(gpr.R(n), WA); else ORR(EncodeRegTo64(gpr.R(n)), SP, XA, ArithOption(XA, ST_LSR, 32)); gpr.Unlock(WA, WB); break; } } gpr.BindToRegister(d, false); if (iIndex == SPR_TU) ORR(EncodeRegTo64(gpr.R(d)), SP, XA, ArithOption(XA, ST_LSR, 32)); else MOV(gpr.R(d), WA); gpr.Unlock(WA, WB); } break; case SPR_XER: { gpr.BindToRegister(d, false); ARM64Reg RD = gpr.R(d); ARM64Reg WA = gpr.GetReg(); LDRH(INDEX_UNSIGNED, RD, X29, PPCSTATE_OFF(xer_stringctrl)); LDRB(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(xer_ca)); ORR(RD, RD, WA, ArithOption(WA, ST_LSL, XER_CA_SHIFT)); LDRB(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(xer_so_ov)); ORR(RD, RD, WA, ArithOption(WA, ST_LSL, XER_OV_SHIFT)); gpr.Unlock(WA); } break; case SPR_WPAR: case SPR_DEC: FALLBACK_IF(true); default: gpr.BindToRegister(d, false); ARM64Reg RD = gpr.R(d); LDR(INDEX_UNSIGNED, RD, X29, PPCSTATE_OFF(spr) + iIndex * 4); break; } }
void JitILBase::reg_imm(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITIntegerOff); int d = inst.RD, a = inst.RA, s = inst.RS; IREmitter::InstLoc val, test, c; switch (inst.OPCD) { case 14: // addi val = ibuild.EmitIntConst(inst.SIMM_16); if (a) val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), val); ibuild.EmitStoreGReg(val, d); break; case 15: // addis val = ibuild.EmitIntConst(inst.SIMM_16 << 16); if (a) val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), val); ibuild.EmitStoreGReg(val, d); break; case 24: // ori val = ibuild.EmitIntConst(inst.UIMM); val = ibuild.EmitOr(ibuild.EmitLoadGReg(s), val); ibuild.EmitStoreGReg(val, a); break; case 25: // oris val = ibuild.EmitIntConst(inst.UIMM << 16); val = ibuild.EmitOr(ibuild.EmitLoadGReg(s), val); ibuild.EmitStoreGReg(val, a); break; case 28: // andi val = ibuild.EmitIntConst(inst.UIMM); val = ibuild.EmitAnd(ibuild.EmitLoadGReg(s), val); ibuild.EmitStoreGReg(val, a); ComputeRC(ibuild, val); break; case 29: // andis val = ibuild.EmitIntConst(inst.UIMM << 16); val = ibuild.EmitAnd(ibuild.EmitLoadGReg(s), val); ibuild.EmitStoreGReg(val, a); ComputeRC(ibuild, val); break; case 26: // xori val = ibuild.EmitIntConst(inst.UIMM); val = ibuild.EmitXor(ibuild.EmitLoadGReg(s), val); ibuild.EmitStoreGReg(val, a); break; case 27: // xoris val = ibuild.EmitIntConst(inst.UIMM << 16); val = ibuild.EmitXor(ibuild.EmitLoadGReg(s), val); ibuild.EmitStoreGReg(val, a); break; case 12: // addic case 13: // addic_rc c = ibuild.EmitIntConst(inst.SIMM_16); val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), c); ibuild.EmitStoreGReg(val, d); test = ibuild.EmitICmpUgt(c, val); ibuild.EmitStoreCarry(test); if (inst.OPCD == 13) ComputeRC(ibuild, val); break; default: FALLBACK_IF(true); } }
void Jit64::fcmpx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITFloatingPointOff); FALLBACK_IF(jo.fpAccurateFcmp); //bool ordered = inst.SUBOP10 == 32; int a = inst.FA; int b = inst.FB; int crf = inst.CRFD; fpr.Lock(a,b); fpr.BindToRegister(b, true); // Are we masking sNaN invalid floating point exceptions? If not this could crash if we don't handle the exception? UCOMISD(fpr.R(b).GetSimpleReg(), fpr.R(a)); FixupBranch pNaN, pLesser, pGreater; FixupBranch continue1, continue2, continue3; if (a != b) { // if B > A, goto Lesser's jump target pLesser = J_CC(CC_A); } // if (B != B) or (A != A), goto NaN's jump target pNaN = J_CC(CC_P); if (a != b) { // if B < A, goto Greater's jump target // JB can't precede the NaN check because it doesn't test ZF pGreater = J_CC(CC_B); } // Equal MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x2)); continue1 = J(); // NAN SetJumpTarget(pNaN); MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x1)); if (a != b) { continue2 = J(); // Greater Than SetJumpTarget(pGreater); MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x4)); continue3 = J(); // Less Than SetJumpTarget(pLesser); MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x8)); } SetJumpTarget(continue1); if (a != b) { SetJumpTarget(continue2); SetJumpTarget(continue3); } fpr.UnlockAll(); }
int r300Fallback(GLcontext *ctx) { int i; //FALLBACK_IF(ctx->RenderMode != GL_RENDER); // We do not do SELECT or FEEDBACK (yet ?) #if 0 /* These should work now.. */ FALLBACK_IF(ctx->Color.DitherFlag); FALLBACK_IF(ctx->Color.AlphaEnabled); // GL_ALPHA_TEST FALLBACK_IF(ctx->Color.BlendEnabled); // GL_BLEND FALLBACK_IF(ctx->Polygon.OffsetFill); // GL_POLYGON_OFFSET_FILL #endif FALLBACK_IF(ctx->Polygon.OffsetPoint); // GL_POLYGON_OFFSET_POINT FALLBACK_IF(ctx->Polygon.OffsetLine); // GL_POLYGON_OFFSET_LINE //FALLBACK_IF(ctx->Stencil.Enabled); // GL_STENCIL_TEST //FALLBACK_IF(ctx->Fog.Enabled); // GL_FOG disable as swtcl doesnt seem to support this //FALLBACK_IF(ctx->Polygon.SmoothFlag); // GL_POLYGON_SMOOTH disabling to get blender going FALLBACK_IF(ctx->Polygon.StippleFlag); // GL_POLYGON_STIPPLE FALLBACK_IF(ctx->Multisample.Enabled); // GL_MULTISAMPLE_ARB FALLBACK_IF(ctx->Line.StippleFlag); /* HW doesnt appear to directly support these */ FALLBACK_IF(ctx->Line.SmoothFlag); // GL_LINE_SMOOTH FALLBACK_IF(ctx->Point.SmoothFlag); // GL_POINT_SMOOTH /* Rest could be done with vertex fragments */ if (ctx->Extensions.NV_point_sprite || ctx->Extensions.ARB_point_sprite) FALLBACK_IF(ctx->Point.PointSprite); // GL_POINT_SPRITE_NV for (i = 0; i < ctx->Const.MaxTextureUnits; i++) if (ctx->Texture.Unit[i]._ReallyEnabled & TEXTURE_RECT_BIT) return R300_FALLBACK_TCL; return R300_FALLBACK_NONE; }
void JitILBase::ps_maddXX(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA), op2, op3; val = ibuild.EmitCompactMRegToPacked(val); switch (inst.SUBOP5) { case 14: // madds0 { op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); op2 = ibuild.EmitFPDup0(op2); val = ibuild.EmitFPMul(val, op2); op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); val = ibuild.EmitFPAdd(val, op3); break; } case 15: // madds1 { op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); op2 = ibuild.EmitFPDup1(op2); val = ibuild.EmitFPMul(val, op2); op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); val = ibuild.EmitFPAdd(val, op3); break; } case 28: // msub { op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); val = ibuild.EmitFPMul(val, op2); op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); val = ibuild.EmitFPSub(val, op3); break; } case 29: // madd { op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); val = ibuild.EmitFPMul(val, op2); op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); val = ibuild.EmitFPAdd(val, op3); break; } case 30: // nmsub { op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); val = ibuild.EmitFPMul(val, op2); op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); val = ibuild.EmitFPSub(val, op3); val = ibuild.EmitFPNeg(val); break; } case 31: // nmadd { op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); val = ibuild.EmitFPMul(val, op2); op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); val = ibuild.EmitFPAdd(val, op3); val = ibuild.EmitFPNeg(val); break; } } val = ibuild.EmitExpandPackedToMReg(val); ibuild.EmitStoreFReg(val, inst.FD); }
void Jit64::lfd(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITLoadStoreFloatingOff); FALLBACK_IF(js.memcheck || !inst.RA); int d = inst.RD; int a = inst.RA; s32 offset = (s32)(s16)inst.SIMM_16; gpr.FlushLockX(ABI_PARAM1); gpr.Lock(a); MOV(32, R(ABI_PARAM1), gpr.R(a)); // TODO - optimize. This has to load the previous value - upper double should stay unmodified. fpr.Lock(d); fpr.BindToRegister(d, true); X64Reg xd = fpr.RX(d); if (cpu_info.bSSSE3) { #if _M_X86_64 MOVQ_xmm(XMM0, MComplex(RBX, ABI_PARAM1, SCALE_1, offset)); #else AND(32, R(ABI_PARAM1), Imm32(Memory::MEMVIEW32_MASK)); MOVQ_xmm(XMM0, MDisp(ABI_PARAM1, (u32)Memory::base + offset)); #endif PSHUFB(XMM0, M((void *)bswapShuffle1x8Dupe)); MOVSD(xd, R(XMM0)); } else { #if _M_X86_64 LoadAndSwap(64, EAX, MComplex(RBX, ABI_PARAM1, SCALE_1, offset)); MOV(64, M(&temp64), R(EAX)); MEMCHECK_START MOVSD(XMM0, M(&temp64)); MOVSD(xd, R(XMM0)); MEMCHECK_END #else AND(32, R(ABI_PARAM1), Imm32(Memory::MEMVIEW32_MASK)); MOV(32, R(EAX), MDisp(ABI_PARAM1, (u32)Memory::base + offset)); BSWAP(32, EAX); MOV(32, M((void*)((u8 *)&temp64+4)), R(EAX)); MEMCHECK_START MOV(32, R(EAX), MDisp(ABI_PARAM1, (u32)Memory::base + offset + 4)); BSWAP(32, EAX); MOV(32, M(&temp64), R(EAX)); MOVSD(XMM0, M(&temp64)); MOVSD(xd, R(XMM0)); MEMCHECK_END #endif } gpr.UnlockAll(); gpr.UnlockAllX(); fpr.UnlockAll(); }
void Jit64::stfd(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITLoadStoreFloatingOff); FALLBACK_IF(js.memcheck || !inst.RA); int s = inst.RS; int a = inst.RA; u32 mem_mask = Memory::ADDR_MASK_HW_ACCESS; if (Core::g_CoreStartupParameter.bMMU || Core::g_CoreStartupParameter.bTLBHack) { mem_mask |= Memory::ADDR_MASK_MEM1; } #ifdef ENABLE_MEM_CHECK if (Core::g_CoreStartupParameter.bEnableDebugging) { mem_mask |= Memory::EXRAM_MASK; } #endif gpr.FlushLockX(ABI_PARAM1); gpr.Lock(a); fpr.Lock(s); gpr.BindToRegister(a, true, false); s32 offset = (s32)(s16)inst.SIMM_16; LEA(32, ABI_PARAM1, MDisp(gpr.R(a).GetSimpleReg(), offset)); TEST(32, R(ABI_PARAM1), Imm32(mem_mask)); FixupBranch safe = J_CC(CC_NZ); // Fast routine if (cpu_info.bSSSE3) { MOVAPD(XMM0, fpr.R(s)); PSHUFB(XMM0, M((void*)bswapShuffle1x8)); #if _M_X86_64 MOVQ_xmm(MComplex(RBX, ABI_PARAM1, SCALE_1, 0), XMM0); #else AND(32, R(ECX), Imm32(Memory::MEMVIEW32_MASK)); MOVQ_xmm(MDisp(ABI_PARAM1, (u32)Memory::base), XMM0); #endif } else { MOVAPD(XMM0, fpr.R(s)); MOVD_xmm(R(EAX), XMM0); UnsafeWriteRegToReg(EAX, ABI_PARAM1, 32, 4); PSRLQ(XMM0, 32); MOVD_xmm(R(EAX), XMM0); UnsafeWriteRegToReg(EAX, ABI_PARAM1, 32, 0); } FixupBranch exit = J(true); SetJumpTarget(safe); // Safe but slow routine MOVAPD(XMM0, fpr.R(s)); PSRLQ(XMM0, 32); MOVD_xmm(R(EAX), XMM0); SafeWriteRegToReg(EAX, ABI_PARAM1, 32, 0, RegistersInUse() | (1 << (16 + XMM0))); MOVAPD(XMM0, fpr.R(s)); MOVD_xmm(R(EAX), XMM0); LEA(32, ABI_PARAM1, MDisp(gpr.R(a).GetSimpleReg(), offset)); SafeWriteRegToReg(EAX, ABI_PARAM1, 32, 4, RegistersInUse()); SetJumpTarget(exit); gpr.UnlockAll(); gpr.UnlockAllX(); fpr.UnlockAll(); }
static int r300Fallback(GLcontext * ctx) { r300ContextPtr r300 = R300_CONTEXT(ctx); struct r300_fragment_program *fp = (struct r300_fragment_program *) (char *)ctx->FragmentProgram._Current; if (fp) { if (!fp->translated) r300TranslateFragmentShader(r300, fp); FALLBACK_IF(!fp->translated); } FALLBACK_IF(ctx->RenderMode != GL_RENDER); FALLBACK_IF(ctx->Stencil._TestTwoSide && (ctx->Stencil.Ref[0] != ctx->Stencil.Ref[1] || ctx->Stencil.ValueMask[0] != ctx->Stencil.ValueMask[1] || ctx->Stencil.WriteMask[0] != ctx->Stencil.WriteMask[1])); FALLBACK_IF(ctx->Color.ColorLogicOpEnabled); if (ctx->Extensions.NV_point_sprite || ctx->Extensions.ARB_point_sprite) FALLBACK_IF(ctx->Point.PointSprite); if (!r300->disable_lowimpact_fallback) { FALLBACK_IF(ctx->Polygon.OffsetPoint); FALLBACK_IF(ctx->Polygon.OffsetLine); FALLBACK_IF(ctx->Polygon.StippleFlag); FALLBACK_IF(ctx->Multisample.Enabled); FALLBACK_IF(ctx->Line.StippleFlag); FALLBACK_IF(ctx->Line.SmoothFlag); FALLBACK_IF(ctx->Point.SmoothFlag); } return R300_FALLBACK_NONE; }