summaryrefslogtreecommitdiffstats
path: root/src/video_core/renderer_opengl/gl_rasterizer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/renderer_opengl/gl_rasterizer.cpp')
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp94
1 files changed, 91 insertions, 3 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 911890f16..f217a265b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -66,6 +66,12 @@ RasterizerOpenGL::RasterizerOpenGL() {
has_ARB_separate_shader_objects = false;
has_ARB_vertex_attrib_binding = false;
+ // Create sampler objects
+ for (size_t i = 0; i < texture_samplers.size(); ++i) {
+ texture_samplers[i].Create();
+ state.texture_units[i].sampler = texture_samplers[i].sampler.handle;
+ }
+
GLint ext_num;
glGetIntegerv(GL_NUM_EXTENSIONS, &ext_num);
for (GLint i = 0; i < ext_num; i++) {
@@ -270,7 +276,9 @@ void RasterizerOpenGL::DrawArrays() {
// TODO(bunnei): Sync framebuffer_scale uniform here
// TODO(bunnei): Sync scissorbox uniform(s) here
- // TODO(bunnei): Sync and bind the texture surfaces
+
+ // Sync and bind the texture surfaces
+ BindTextures();
// Sync and bind the shader
if (shader_dirty) {
@@ -374,6 +382,39 @@ void RasterizerOpenGL::DrawArrays() {
}
}
+void RasterizerOpenGL::BindTextures() {
+ using Regs = Tegra::Engines::Maxwell3D::Regs;
+ auto maxwell3d = Core::System::GetInstance().GPU().Get3DEngine();
+
+ // Each Maxwell shader stage can have an arbitrary number of textures, but we're limited to a
+ // certain number in OpenGL. We try to only use the minimum amount of host textures by not
+ // keeping a 1:1 relation between guest texture ids and host texture ids, ie, guest texture id 8
+ // can be host texture id 0 if it's the only texture used in the guest shader program.
+ u32 host_texture_index = 0;
+ for (u32 stage = 0; stage < Regs::MaxShaderStage; ++stage) {
+ ASSERT(host_texture_index < texture_samplers.size());
+ const auto textures = maxwell3d.GetStageTextures(static_cast<Regs::ShaderStage>(stage));
+ for (unsigned texture_index = 0; texture_index < textures.size(); ++texture_index) {
+ const auto& texture = textures[texture_index];
+
+ if (texture.enabled) {
+ texture_samplers[host_texture_index].SyncWithConfig(texture.tsc);
+ Surface surface = res_cache.GetTextureSurface(texture);
+ if (surface != nullptr) {
+ state.texture_units[host_texture_index].texture_2d = surface->texture.handle;
+ } else {
+ // Can occur when texture addr is null or its memory is unmapped/invalid
+ state.texture_units[texture_index].texture_2d = 0;
+ }
+
+ ++host_texture_index;
+ } else {
+ state.texture_units[texture_index].texture_2d = 0;
+ }
+ }
+ }
+}
+
void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 id) {}
void RasterizerOpenGL::FlushAll() {
@@ -452,6 +493,44 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& framebu
return true;
}
+void RasterizerOpenGL::SamplerInfo::Create() {
+ sampler.Create();
+ mag_filter = min_filter = Tegra::Texture::TextureFilter::Linear;
+ wrap_u = wrap_v = Tegra::Texture::WrapMode::Wrap;
+ border_color_r = border_color_g = border_color_b = border_color_a = 0;
+
+ // default is GL_LINEAR_MIPMAP_LINEAR
+ glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ // Other attributes have correct defaults
+}
+
+void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntry& config) {
+ GLuint s = sampler.handle;
+
+ if (mag_filter != config.mag_filter) {
+ mag_filter = config.mag_filter;
+ glSamplerParameteri(s, GL_TEXTURE_MAG_FILTER, MaxwellToGL::TextureFilterMode(mag_filter));
+ }
+ if (min_filter != config.min_filter) {
+ min_filter = config.min_filter;
+ glSamplerParameteri(s, GL_TEXTURE_MIN_FILTER, MaxwellToGL::TextureFilterMode(min_filter));
+ }
+
+ if (wrap_u != config.wrap_u) {
+ wrap_u = config.wrap_u;
+ glSamplerParameteri(s, GL_TEXTURE_WRAP_S, MaxwellToGL::WrapMode(wrap_u));
+ }
+ if (wrap_v != config.wrap_v) {
+ wrap_v = config.wrap_v;
+ glSamplerParameteri(s, GL_TEXTURE_WRAP_T, MaxwellToGL::WrapMode(wrap_v));
+ }
+
+ if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border) {
+ // TODO(Subv): Implement border color
+ ASSERT(false);
+ }
+}
+
void RasterizerOpenGL::SetShader() {
// TODO(bunnei): The below sets up a static test shader for passing untransformed vertices to
// OpenGL for rendering. This should be removed/replaced when we start emulating Maxwell
@@ -479,10 +558,10 @@ void main() {
in vec2 frag_tex_coord;
out vec4 color;
-uniform sampler2D color_texture;
+uniform sampler2D tex[32];
void main() {
- color = vec4(1.0, 0.0, 1.0, 0.0);
+ color = texture(tex[0], frag_tex_coord);
}
)";
@@ -503,6 +582,15 @@ void main() {
state.draw.shader_program = test_shader.shader.handle;
state.Apply();
+ for (u32 texture = 0; texture < texture_samplers.size(); ++texture) {
+ // Set the texture samplers to correspond to different texture units
+ std::string uniform_name = "tex[" + std::to_string(texture) + "]";
+ GLint uniform_tex = glGetUniformLocation(test_shader.shader.handle, uniform_name.c_str());
+ if (uniform_tex != -1) {
+ glUniform1i(uniform_tex, TextureUnits::MaxwellTexture(texture).id);
+ }
+ }
+
if (has_ARB_separate_shader_objects) {
state.draw.shader_program = 0;
state.Apply();