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; }
static void wiiu_font_render_line( video_frame_info_t *video_info, wiiu_font_t* font, const char* msg, unsigned msg_len, float scale, const unsigned int color, float pos_x, float pos_y, unsigned text_align) { unsigned i; wiiu_video_t* wiiu = (wiiu_video_t*)video_driver_get_ptr(false); unsigned width = video_info->width; unsigned height = video_info->height; int x = roundf(pos_x * width); int y = roundf((1.0f - pos_y) * height); int delta_x = 0; int delta_y = 0; if(wiiu->vertex_cache.current + (msg_len * 4) > wiiu->vertex_cache.size) return; switch (text_align) { case TEXT_ALIGN_RIGHT: x -= wiiu_font_get_message_width(font, msg, msg_len, scale); break; case TEXT_ALIGN_CENTER: x -= wiiu_font_get_message_width(font, msg, msg_len, scale) / 2; break; } position_t* pos = wiiu->vertex_cache.positions + wiiu->vertex_cache.current; tex_coord_t* coord = wiiu->vertex_cache.tex_coords + wiiu->vertex_cache.current; for (i = 0; i < msg_len; i++) { int off_x, off_y, tex_x, tex_y, width, height; const char* msg_tmp = &msg[i]; unsigned code = utf8_walk(&msg_tmp); unsigned skip = msg_tmp - &msg[i]; if (skip > 1) i += skip - 1; const struct font_glyph* glyph = font->font_driver->get_glyph(font->font_data, code); if (!glyph) /* Do something smarter here ... */ glyph = font->font_driver->get_glyph(font->font_data, '?'); if (!glyph) continue; off_x = glyph->draw_offset_x; off_y = glyph->draw_offset_y; tex_x = glyph->atlas_offset_x; tex_y = glyph->atlas_offset_y; width = glyph->width; height = glyph->height; float x0 = x + off_x + delta_x * scale; float y0 = y + off_y + delta_y * scale + height * scale; float u0 = tex_x; float v0 = tex_y; float x1 = x0 + width * scale; float y1 = y0 - height * scale; float u1 = u0 + width; float v1 = v0 + height; pos[0].x = (2.0f * x0 / wiiu->color_buffer.surface.width) - 1.0f; pos[0].y = (-2.0f * y0 / wiiu->color_buffer.surface.height) + 1.0f; pos[1].x = (2.0f * x1 / wiiu->color_buffer.surface.width) - 1.0f;; pos[1].y = (-2.0f * y0 / wiiu->color_buffer.surface.height) + 1.0f; pos[2].x = (2.0f * x1 / wiiu->color_buffer.surface.width) - 1.0f;; pos[2].y = (-2.0f * y1 / wiiu->color_buffer.surface.height) + 1.0f; pos[3].x = (2.0f * x0 / wiiu->color_buffer.surface.width) - 1.0f;; pos[3].y = (-2.0f * y1 / wiiu->color_buffer.surface.height) + 1.0f; pos += 4; coord[0].u = u0 / font->texture.surface.width; coord[0].v = v1 / font->texture.surface.height; coord[1].u = u1 / font->texture.surface.width; coord[1].v = v1 / font->texture.surface.height; coord[2].u = u1 / font->texture.surface.width; coord[2].v = v0 / font->texture.surface.height; coord[3].u = u0 / font->texture.surface.width; coord[3].v = v0 / font->texture.surface.height; coord += 4; delta_x += glyph->advance_x; delta_y += glyph->advance_y; } int count = pos - wiiu->vertex_cache.positions - wiiu->vertex_cache.current; if (!count) return; GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, wiiu->vertex_cache.positions + wiiu->vertex_cache.current, count * sizeof(position_t)); GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, wiiu->vertex_cache.tex_coords + wiiu->vertex_cache.current, count * sizeof(tex_coord_t)); if(font->atlas->dirty) { for (i = 0; (i < font->atlas->height) && (i < font->texture.surface.height); i++) memcpy(font->texture.surface.image + (i * font->texture.surface.pitch), font->atlas->buffer + (i * font->atlas->width), font->atlas->width); GX2Invalidate(GX2_INVALIDATE_MODE_CPU_TEXTURE, font->texture.surface.image, font->texture.surface.imageSize); font->atlas->dirty = false; } #if 0 printf("%s\n", msg); DEBUG_VAR(color); #endif GX2SetPixelTexture(&font->texture, wiiu->shader->sampler.location); GX2SetBlendConstantColor(((color >> 0) & 0xFF) / 255.0f, ((color >> 8) & 0xFF) / 255.0f, ((color >> 16) & 0xFF) / 255.0f, ((color >> 24) & 0xFF) / 255.0f); GX2SetBlendControl(GX2_RENDER_TARGET_0, GX2_BLEND_MODE_BLEND_FACTOR, 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); GX2DrawEx(GX2_PRIMITIVE_MODE_QUADS, count, wiiu->vertex_cache.current, 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); wiiu->vertex_cache.current = pos - wiiu->vertex_cache.positions; }