void GX2InitShader(GX2Shader *shader) { if (shader->fs.program) return; shader->fs.size = GX2CalcFetchShaderSizeEx(shader->vs.attribVarCount, GX2_FETCH_SHADER_TESSELLATION_NONE, GX2_TESSELLATION_MODE_DISCRETE); #ifdef GX2_CAN_ACCESS_DATA_SECTION shader->fs.program = MEM2_alloc(shader->fs.size, GX2_SHADER_ALIGNMENT); #else shader->fs.program = MEM2_alloc(shader->fs.size + sizeof(org_programs_t), GX2_SHADER_ALIGNMENT); #endif GX2InitFetchShaderEx(&shader->fs, (uint8_t *)shader->fs.program, shader->vs.attribVarCount, shader->attribute_stream, GX2_FETCH_SHADER_TESSELLATION_NONE, GX2_TESSELLATION_MODE_DISCRETE); GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, shader->fs.program, shader->fs.size); #ifndef GX2_CAN_ACCESS_DATA_SECTION org_programs_t *org = (org_programs_t *)(shader->fs.program + shader->fs.size); org->vs_program = shader->vs.program; org->ps_program = shader->ps.program; org->gs_program = shader->gs.program; org->gs_copy_program = shader->gs.copyProgram; shader->vs.program = MEM2_alloc(shader->vs.size, GX2_SHADER_ALIGNMENT); memcpy(shader->vs.program, org->vs_program, shader->vs.size); GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, shader->vs.program, shader->vs.size); shader->ps.program = MEM2_alloc(shader->ps.size, GX2_SHADER_ALIGNMENT); memcpy(shader->ps.program, org->ps_program, shader->ps.size); GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, shader->ps.program, shader->ps.size); if (org->gs_program) { shader->gs.program = MEM2_alloc(shader->gs.size, GX2_SHADER_ALIGNMENT); memcpy(shader->gs.program, org->gs_program, shader->gs.size); GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, shader->gs.program, shader->gs.size); shader->gs.copyProgram = MEM2_alloc(shader->gs.copyProgramSize, GX2_SHADER_ALIGNMENT); memcpy(shader->gs.copyProgram, org->gs_copy_program, shader->gs.copyProgramSize); GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, shader->gs.copyProgram, shader->gs.copyProgramSize); } #endif }
void GX2InitFetchShaderEx(GX2FetchShader *fetchShader, void *buffer, uint32_t count, GX2AttribStream *attribs, GX2FetchShaderType::Type type, GX2TessellationMode::Mode tessMode) { fetchShader->data = buffer; fetchShader->size = GX2CalcFetchShaderSizeEx(count, type, tessMode); fetchShader->attribCount = count; auto dataPtr = (FetchShaderInfo*)buffer; dataPtr->type = type; dataPtr->tessMode = tessMode; memcpy(dataPtr->attribs, attribs, count * sizeof(GX2AttribStream)); }
static void* wiiu_gfx_init(const video_info_t* video, const input_driver_t** input, void** input_data) { int i; *input = NULL; *input_data = NULL; wiiu_video_t* wiiu = calloc(1, sizeof(*wiiu)); if (!wiiu) return NULL; void* wiiuinput = NULL; if (input && input_data) { wiiuinput = input_wiiu.init(); *input = wiiuinput ? &input_wiiu : NULL; *input_data = wiiuinput; } /* video init */ wiiu->cmd_buffer = MEM2_alloc(0x400000, 0x40); u32 init_attributes[] = { GX2_INIT_CMD_BUF_BASE, (u32)wiiu->cmd_buffer, GX2_INIT_CMD_BUF_POOL_SIZE, 0x400000, GX2_INIT_ARGC, 0, GX2_INIT_ARGV, 0, GX2_INIT_END }; GX2Init(init_attributes); /* setup scanbuffers */ u32 size = 0; u32 tmp = 0; wiiu->render_mode = wiiu_render_mode_map[GX2GetSystemTVScanMode()]; GX2CalcTVSize(wiiu->render_mode.mode, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, GX2_BUFFERING_MODE_DOUBLE, &size, &tmp); wiiu->tv_scan_buffer = MEMBucket_alloc(size, GX2_SCAN_BUFFER_ALIGNMENT); GX2Invalidate(GX2_INVALIDATE_MODE_CPU, wiiu->tv_scan_buffer, size); GX2SetTVBuffer(wiiu->tv_scan_buffer, size, wiiu->render_mode.mode, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, GX2_BUFFERING_MODE_DOUBLE); GX2CalcDRCSize(GX2_DRC_RENDER_MODE_SINGLE, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, GX2_BUFFERING_MODE_DOUBLE, &size, &tmp); wiiu->drc_scan_buffer = MEMBucket_alloc(size, GX2_SCAN_BUFFER_ALIGNMENT); GX2Invalidate(GX2_INVALIDATE_MODE_CPU, wiiu->drc_scan_buffer, size); GX2SetDRCBuffer(wiiu->drc_scan_buffer, size, GX2_DRC_RENDER_MODE_SINGLE, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, GX2_BUFFERING_MODE_DOUBLE); memset(&wiiu->color_buffer, 0, sizeof(GX2ColorBuffer)); wiiu->color_buffer.surface.dim = GX2_SURFACE_DIM_TEXTURE_2D; wiiu->color_buffer.surface.width = wiiu->render_mode.width; wiiu->color_buffer.surface.height = wiiu->render_mode.height; wiiu->color_buffer.surface.depth = 1; wiiu->color_buffer.surface.mipLevels = 1; wiiu->color_buffer.surface.format = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8; wiiu->color_buffer.surface.use = GX2_SURFACE_USE_TEXTURE_COLOR_BUFFER_TV; wiiu->color_buffer.viewNumSlices = 1; GX2CalcSurfaceSizeAndAlignment(&wiiu->color_buffer.surface); GX2InitColorBufferRegs(&wiiu->color_buffer); wiiu->color_buffer.surface.image = MEM1_alloc(wiiu->color_buffer.surface.imageSize, wiiu->color_buffer.surface.alignment); GX2Invalidate(GX2_INVALIDATE_MODE_CPU, wiiu->color_buffer.surface.image, wiiu->color_buffer.surface.imageSize); wiiu->ctx_state = (GX2ContextState*)MEM2_alloc(sizeof(GX2ContextState), GX2_CONTEXT_STATE_ALIGNMENT); GX2SetupContextStateEx(wiiu->ctx_state, GX2_TRUE); GX2SetContextState(wiiu->ctx_state); GX2SetColorBuffer(&wiiu->color_buffer, GX2_RENDER_TARGET_0); GX2SetViewport(0.0f, 0.0f, wiiu->color_buffer.surface.width, wiiu->color_buffer.surface.height, 0.0f, 1.0f); GX2SetScissor(0, 0, wiiu->color_buffer.surface.width, wiiu->color_buffer.surface.height); GX2SetDepthOnlyControl(GX2_DISABLE, GX2_DISABLE, GX2_COMPARE_FUNC_ALWAYS); GX2SetColorControl(GX2_LOGIC_OP_COPY, 1, GX2_DISABLE, GX2_ENABLE); #if 1 GX2SetBlendControl(GX2_RENDER_TARGET_0, GX2_BLEND_MODE_SRC_ALPHA, GX2_BLEND_MODE_INV_SRC_ALPHA, GX2_BLEND_COMBINE_MODE_ADD, GX2_ENABLE, GX2_BLEND_MODE_SRC_ALPHA, GX2_BLEND_MODE_INV_SRC_ALPHA, GX2_BLEND_COMBINE_MODE_ADD); #else GX2SetBlendControl(GX2_RENDER_TARGET_0, GX2_BLEND_MODE_ONE, GX2_BLEND_MODE_ZERO, GX2_BLEND_COMBINE_MODE_ADD, GX2_DISABLE, GX2_BLEND_MODE_ONE, GX2_BLEND_MODE_ZERO, GX2_BLEND_COMBINE_MODE_ADD); #endif GX2SetCullOnlyControl(GX2_FRONT_FACE_CCW, GX2_DISABLE, GX2_DISABLE); #ifdef GX2_CAN_ACCESS_DATA_SECTION wiiu->shader = &tex_shader; #else /* init shader */ // wiiu->shader = MEM2_alloc(sizeof(*wiiu->shader), GX2_VERTEX_BUFFER_ALIGNMENT); wiiu->shader = MEM2_alloc(sizeof(tex_shader), 0x1000); memcpy(wiiu->shader, &tex_shader, sizeof(tex_shader)); GX2Invalidate(GX2_INVALIDATE_MODE_CPU, wiiu->shader, sizeof(tex_shader)); wiiu->shader->vs.program = MEM2_alloc(wiiu->shader->vs.size, GX2_SHADER_ALIGNMENT); memcpy(wiiu->shader->vs.program, tex_shader.vs.program, wiiu->shader->vs.size); GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, wiiu->shader->vs.program, wiiu->shader->vs.size); wiiu->shader->vs.attribVars = MEM2_alloc(wiiu->shader->vs.attribVarCount * sizeof(GX2AttribVar), GX2_SHADER_ALIGNMENT); memcpy(wiiu->shader->vs.attribVars, tex_shader.vs.attribVars , wiiu->shader->vs.attribVarCount * sizeof(GX2AttribVar)); wiiu->shader->ps.program = MEM2_alloc(wiiu->shader->ps.size, GX2_SHADER_ALIGNMENT); memcpy(wiiu->shader->ps.program, tex_shader.ps.program, wiiu->shader->ps.size); GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, wiiu->shader->ps.program, wiiu->shader->ps.size); wiiu->shader->ps.samplerVars = MEM2_alloc(wiiu->shader->ps.samplerVarCount * sizeof(GX2SamplerVar), GX2_SHADER_ALIGNMENT); memcpy(wiiu->shader->ps.samplerVars, tex_shader.ps.samplerVars, wiiu->shader->ps.samplerVarCount * sizeof(GX2SamplerVar)); #endif wiiu->shader->fs.size = GX2CalcFetchShaderSizeEx(2, GX2_FETCH_SHADER_TESSELLATION_NONE, GX2_TESSELLATION_MODE_DISCRETE); wiiu->shader->fs.program = MEM2_alloc(wiiu->shader->fs.size, GX2_SHADER_ALIGNMENT); GX2InitFetchShaderEx(&wiiu->shader->fs, (uint8_t*)wiiu->shader->fs.program, sizeof(wiiu->shader->attribute_stream) / sizeof(GX2AttribStream), (GX2AttribStream*)&wiiu->shader->attribute_stream, GX2_FETCH_SHADER_TESSELLATION_NONE, GX2_TESSELLATION_MODE_DISCRETE); GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, wiiu->shader->fs.program, wiiu->shader->fs.size); GX2SetVertexShader(&wiiu->shader->vs); GX2SetPixelShader(&wiiu->shader->ps); GX2SetFetchShader(&wiiu->shader->fs); wiiu->position = MEM2_alloc(4 * sizeof(*wiiu->position), GX2_VERTEX_BUFFER_ALIGNMENT); wiiu_set_position(wiiu->position, &wiiu->color_buffer, 0, 0, wiiu->color_buffer.surface.width, wiiu->color_buffer.surface.height); wiiu->tex_coord = MEM2_alloc(4 * sizeof(*wiiu->tex_coord), GX2_VERTEX_BUFFER_ALIGNMENT); wiiu_set_tex_coords(wiiu->tex_coord, &wiiu->texture, 0, 0, wiiu->texture.surface.width, wiiu->texture.surface.height); GX2SetAttribBuffer(0, 4 * sizeof(*wiiu->position), sizeof(*wiiu->position), wiiu->position); GX2SetAttribBuffer(1, 4 * sizeof(*wiiu->tex_coord), sizeof(*wiiu->tex_coord), wiiu->tex_coord); wiiu->menu.position = MEM2_alloc(4 * sizeof(*wiiu->menu.position), GX2_VERTEX_BUFFER_ALIGNMENT); wiiu_set_position(wiiu->menu.position, &wiiu->color_buffer, 0, 0, wiiu->color_buffer.surface.width, wiiu->color_buffer.surface.height); wiiu->menu.tex_coord = MEM2_alloc(4 * sizeof(*wiiu->menu.tex_coord), GX2_VERTEX_BUFFER_ALIGNMENT); wiiu_set_tex_coords(wiiu->menu.tex_coord, &wiiu->menu.texture, 0, 0, wiiu->menu.texture.surface.width, wiiu->menu.texture.surface.height); /* init frame texture */ memset(&wiiu->texture, 0, sizeof(GX2Texture)); wiiu->texture.surface.width = video->input_scale * RARCH_SCALE_BASE; wiiu->texture.surface.height = video->input_scale * RARCH_SCALE_BASE; wiiu->texture.surface.depth = 1; wiiu->texture.surface.dim = GX2_SURFACE_DIM_TEXTURE_2D; wiiu->texture.surface.tileMode = GX2_TILE_MODE_LINEAR_ALIGNED; wiiu->texture.viewNumSlices = 1; wiiu->rgb32 = video->rgb32; if(wiiu->rgb32) { wiiu->texture.surface.format = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8; wiiu->texture.compMap = GX2_COMP_SEL(_G, _B, _A, _1); } else { wiiu->texture.surface.format = GX2_SURFACE_FORMAT_UNORM_R5_G6_B5; wiiu->texture.compMap = GX2_COMP_SEL(_B, _G, _R, _1); } GX2CalcSurfaceSizeAndAlignment(&wiiu->texture.surface); GX2InitTextureRegs(&wiiu->texture); wiiu->texture.surface.image = MEM2_alloc(wiiu->texture.surface.imageSize, wiiu->texture.surface.alignment); memset(wiiu->texture.surface.image, 0x0, wiiu->texture.surface.imageSize); GX2Invalidate(GX2_INVALIDATE_MODE_CPU_TEXTURE, wiiu->texture.surface.image, wiiu->texture.surface.imageSize); /* init menu texture */ memset(&wiiu->menu.texture, 0, sizeof(GX2Texture)); wiiu->menu.texture.surface.width = 512; wiiu->menu.texture.surface.height = 512; wiiu->menu.texture.surface.depth = 1; wiiu->menu.texture.surface.dim = GX2_SURFACE_DIM_TEXTURE_2D; wiiu->menu.texture.surface.format = GX2_SURFACE_FORMAT_UNORM_R4_G4_B4_A4; wiiu->menu.texture.surface.tileMode = GX2_TILE_MODE_LINEAR_ALIGNED; wiiu->menu.texture.viewNumSlices = 1; wiiu->menu.texture.compMap = GX2_COMP_SEL(_A, _R, _G, _B); GX2CalcSurfaceSizeAndAlignment(&wiiu->menu.texture.surface); GX2InitTextureRegs(&wiiu->menu.texture); wiiu->menu.texture.surface.image = MEM2_alloc(wiiu->menu.texture.surface.imageSize, wiiu->menu.texture.surface.alignment); memset(wiiu->menu.texture.surface.image, 0x0, wiiu->menu.texture.surface.imageSize); GX2Invalidate(GX2_INVALIDATE_MODE_CPU_TEXTURE, wiiu->menu.texture.surface.image, wiiu->menu.texture.surface.imageSize); /* init samplers */ GX2InitSampler(&wiiu->sampler_nearest, GX2_TEX_CLAMP_MODE_CLAMP, GX2_TEX_XY_FILTER_MODE_POINT); GX2InitSampler(&wiiu->sampler_linear, GX2_TEX_CLAMP_MODE_CLAMP, GX2_TEX_XY_FILTER_MODE_LINEAR); /* set Texture and Sampler */ GX2SetPixelTexture(&wiiu->texture, wiiu->shader->sampler.location); GX2SetPixelSampler(&wiiu->sampler_linear, wiiu->shader->sampler.location); /* clear leftover image */ GX2ClearColor(&wiiu->color_buffer, 0.0f, 0.0f, 0.0f, 1.0f); GX2CopyColorBufferToScanBuffer(&wiiu->color_buffer, GX2_SCAN_TARGET_DRC); GX2CopyColorBufferToScanBuffer(&wiiu->color_buffer, GX2_SCAN_TARGET_TV); GX2SwapScanBuffers(); GX2Flush(); GX2WaitForVsync(); GX2SetTVEnable(GX2_ENABLE); GX2SetDRCEnable(GX2_ENABLE); wiiu->keep_aspect = true; wiiu->should_resize = true; wiiu->smooth = video->smooth; wiiu->vsync = video->vsync; GX2SetSwapInterval(!!video->vsync); wiiu->vp.x = 0; wiiu->vp.y = 0; wiiu->vp.width = 854; wiiu->vp.height = 480; wiiu->vp.full_width = 854; wiiu->vp.full_height = 480; video_driver_set_size(&wiiu->vp.width, &wiiu->vp.height); float refresh_rate = 60.0f / 1.001f; driver_ctl(RARCH_DRIVER_CTL_SET_REFRESH_RATE, &refresh_rate); return wiiu; }
void GX2InitFetchShaderEx(GX2FetchShader *fetchShader, uint8_t *buffer, uint32_t attribCount, GX2AttribStream *attribs, GX2FetchShaderType type, GX2TessellationMode tessMode) { if (type != GX2FetchShaderType::NoTessellation) { decaf_abort(fmt::format("Invalid GX2FetchShaderType {}", enumAsString(type))); } if (tessMode != GX2TessellationMode::Discrete) { decaf_abort(fmt::format("Invalid GX2TessellationMode {}", enumAsString(tessMode))); } auto someTessVar1 = 128u; auto someTessVar2 = 128u; auto numGPRs = 0u; auto barrier = false; // Calculate instruction pointers auto fetchCount = GX2FSCalcNumFetchInsts(attribCount, type); auto aluCount = 0; // GX2FSCalcNumAluInsts(type, tessMode); auto cfCount = GX2FSCalcNumCFInsts(fetchCount, type); auto fetchSize = fetchCount * sizeof(latte::VertexFetchInst); auto cfSize = cfCount * sizeof(latte::ControlFlowInst); auto aluSize = aluCount * sizeof(latte::AluInst); auto cfOffset = 0u; auto aluOffset = cfSize; auto fetchOffset = align_up(cfSize + aluSize, 0x10u); auto cfPtr = reinterpret_cast<latte::ControlFlowInst *>(buffer + cfOffset); auto aluPtr = reinterpret_cast<latte::AluInst *>(buffer + aluOffset); auto fetchPtr = reinterpret_cast<latte::VertexFetchInst *>(buffer + fetchOffset); // Setup fetch shader fetchShader->type = type; fetchShader->attribCount = attribCount; fetchShader->data = buffer; fetchShader->size = GX2CalcFetchShaderSizeEx(attribCount, type, tessMode); // Generate fetch instructions auto indexMap = GX2FSGetIndexGprMap(type, tessMode); for (auto i = 0u; i < attribCount; ++i) { latte::VertexFetchInst vfetch; auto &attrib = attribs[i]; std::memset(&vfetch, 0, sizeof(vfetch)); if (attrib.buffer == 16) { // TODO: Figure out what these vars are for if (attrib.offset) { if (attrib.offset == 1) { someTessVar1 = attrib.location; } } else { someTessVar2 = attrib.location; } } else { // Semantic vertex fetch vfetch.word0 = vfetch.word0 .VTX_INST(latte::SQ_VTX_INST_SEMANTIC) .BUFFER_ID(latte::SQ_RES_OFFSET::VS_ATTRIB_RESOURCE_0 + attrib.buffer - latte::SQ_RES_OFFSET::VS_TEX_RESOURCE_0); vfetch.word2 = vfetch.word2 .OFFSET(attribs[i].offset); if (attrib.type) { auto selX = latte::SQ_SEL::SEL_X; auto fetchType = latte::SQ_VTX_FETCH_TYPE::VERTEX_DATA; if (attrib.type == GX2AttribIndexType::PerInstance) { if (attrib.aluDivisor == 1) { fetchType = latte::SQ_VTX_FETCH_TYPE::INSTANCE_DATA; selX = latte::SQ_SEL::SEL_W; } else if (attrib.aluDivisor == fetchShader->divisors[0]) { fetchType = latte::SQ_VTX_FETCH_TYPE::INSTANCE_DATA; selX = latte::SQ_SEL::SEL_Y; } else if (attrib.aluDivisor == fetchShader->divisors[1]) { fetchType = latte::SQ_VTX_FETCH_TYPE::INSTANCE_DATA; selX = latte::SQ_SEL::SEL_Z; } else { fetchShader->divisors[fetchShader->numDivisors] = attrib.aluDivisor; if (fetchShader->numDivisors == 0) { selX = latte::SQ_SEL::SEL_Y; } else if (fetchShader->numDivisors == 1) { selX = latte::SQ_SEL::SEL_Z; } fetchShader->numDivisors++; } } vfetch.word0 = vfetch.word0 .FETCH_TYPE(fetchType) .SRC_SEL_X(selX); } else { vfetch.word0 = vfetch.word0 .SRC_GPR(indexMap[0].gpr) .SRC_SEL_X(static_cast<latte::SQ_SEL>(indexMap[0].chan)); } // Setup dest vfetch.gpr = vfetch.gpr .DST_GPR(attrib.location); vfetch.word1 = vfetch.word1 .DST_SEL_W(static_cast<latte::SQ_SEL>(attrib.mask & 0x7)) .DST_SEL_Z(static_cast<latte::SQ_SEL>((attrib.mask >> 8) & 0x7)) .DST_SEL_Y(static_cast<latte::SQ_SEL>((attrib.mask >> 16) & 0x7)) .DST_SEL_X(static_cast<latte::SQ_SEL>((attrib.mask >> 24) & 0x7)); // Setup mega fetch vfetch.word2 = vfetch.word2 .MEGA_FETCH(1); vfetch.word0 = vfetch.word0 .MEGA_FETCH_COUNT(internal::getAttribFormatBytes(attrib.format) - 1); // Setup format auto dataFormat = internal::getAttribFormatDataFormat(attrib.format); auto numFormat = latte::SQ_NUM_FORMAT::NORM; auto formatComp = latte::SQ_FORMAT_COMP::UNSIGNED; if (attribs[i].format & GX2AttribFormatFlags::SCALED) { numFormat = latte::SQ_NUM_FORMAT::SCALED; } else if (attribs[i].format & GX2AttribFormatFlags::INTEGER) { numFormat = latte::SQ_NUM_FORMAT::INT; } if (attribs[i].format & GX2AttribFormatFlags::SIGNED) { formatComp = latte::SQ_FORMAT_COMP::SIGNED; } vfetch.word1 = vfetch.word1 .DATA_FORMAT(dataFormat) .NUM_FORMAT_ALL(numFormat) .FORMAT_COMP_ALL(formatComp); auto swapMode = internal::getSwapModeEndian(attribs[i].endianSwap & 3); if (attribs[i].endianSwap == latte::SQ_ENDIAN::AUTO) { swapMode = internal::getAttribFormatEndian(attribs[i].format); } vfetch.word2 = vfetch.word2 .ENDIAN_SWAP(swapMode); // Append to program *(fetchPtr++) = vfetch; // Add extra tesselation vertex fetches if (type != GX2FetchShaderType::NoTessellation && attrib.type != GX2AttribIndexType::PerInstance) { auto perAttrib = GX2FetchInstsPerAttrib(type); for (auto j = 1u; j < perAttrib; ++j) { latte::VertexFetchInst vfetch2 = vfetch; // Update src/dst vfetch2.word0 = vfetch2.word0 .SRC_GPR(indexMap[j].gpr) .SRC_SEL_X(static_cast<latte::SQ_SEL>(indexMap[j].chan)); vfetch2.gpr = vfetch2.gpr .DST_GPR(j + attrib.location); // Append to program *(fetchPtr++) = vfetch; } } } } // Generate tessellation ALU ops if (type != GX2FetchShaderType::NoTessellation) { numGPRs = 2; if (tessMode == GX2TessellationMode::Adaptive) { switch (type) { case GX2FetchShaderType::LineTessellation: numGPRs = 3; break; case GX2FetchShaderType::TriangleTessellation: numGPRs = 7; break; case GX2FetchShaderType::QuadTessellation: numGPRs = 7; break; } } // TODO: GX2FSGenTessAluOps barrier = true; } // Generate a VTX CF per 16 VFETCH if (fetchCount) { for (auto i = 0u; i < cfCount - 1; ++i) { auto fetches = FetchesPerControlFlow; if (fetchCount < (i + 1) * FetchesPerControlFlow) { // Don't overrun our fetches! fetches = fetchCount % FetchesPerControlFlow; } latte::ControlFlowInst inst; std::memset(&inst, 0, sizeof(inst)); inst.word0.ADDR = static_cast<uint32_t>((fetchOffset + sizeof(latte::VertexFetchInst) * i * FetchesPerControlFlow) / 8); inst.word1 = inst.word1 .COUNT((fetches - 1) & 0x7) .COUNT_3(((fetches - 1) >> 3) & 0x1) .CF_INST(latte::SQ_CF_INST_VTX_TC) .BARRIER(barrier ? 1 : 0); *(cfPtr++) = inst; } } // Generate tessellation "post" ALU ops if (numGPRs) { // TODO: GX2FSGenPostAluOps } // Generate an EOP latte::ControlFlowInst eop; std::memset(&eop, 0, sizeof(eop)); eop.word1 = eop.word1 .BARRIER(1) .CF_INST(latte::SQ_CF_INST_RETURN); *(cfPtr++) = eop; // Set sq_pgm_resources_fs auto sq_pgm_resources_fs = fetchShader->regs.sq_pgm_resources_fs.value(); sq_pgm_resources_fs = sq_pgm_resources_fs .NUM_GPRS(numGPRs); fetchShader->regs.sq_pgm_resources_fs = sq_pgm_resources_fs; GX2Invalidate(GX2InvalidateMode::CPU, fetchShader->data, fetchShader->size); }