diff options
| author | 2014-12-20 12:40:06 -0500 | |
|---|---|---|
| committer | 2014-12-20 12:40:06 -0500 | |
| commit | acabd7be82b4174a3adab0771df6320bdbc5a85b (patch) | |
| tree | c47c2f68f50005bfb5c4003831f3977aec0be3ca /src/video_core/rasterizer.cpp | |
| parent | Merge pull request #315 from chinhodado/master (diff) | |
| parent | Pica/VertexShader: Promote a log message to critical status. (diff) | |
| download | yuzu-acabd7be82b4174a3adab0771df6320bdbc5a85b.tar.gz yuzu-acabd7be82b4174a3adab0771df6320bdbc5a85b.tar.xz yuzu-acabd7be82b4174a3adab0771df6320bdbc5a85b.zip | |
Merge pull request #284 from neobrain/pica_progress
Pica progress: Texturing, shaders, cleanups & more
Diffstat (limited to 'src/video_core/rasterizer.cpp')
| -rw-r--r-- | src/video_core/rasterizer.cpp | 164 |
1 files changed, 98 insertions, 66 deletions
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index b7e04a560..bf9c36661 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp | |||
| @@ -18,7 +18,7 @@ namespace Pica { | |||
| 18 | namespace Rasterizer { | 18 | namespace Rasterizer { |
| 19 | 19 | ||
| 20 | static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { | 20 | static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { |
| 21 | u32* color_buffer = (u32*)Memory::GetPointer(registers.framebuffer.GetColorBufferAddress()); | 21 | u32* color_buffer = reinterpret_cast<u32*>(Memory::GetPointer(PAddrToVAddr(registers.framebuffer.GetColorBufferPhysicalAddress()))); |
| 22 | u32 value = (color.a() << 24) | (color.r() << 16) | (color.g() << 8) | color.b(); | 22 | u32 value = (color.a() << 24) | (color.r() << 16) | (color.g() << 8) | color.b(); |
| 23 | 23 | ||
| 24 | // Assuming RGBA8 format until actual framebuffer format handling is implemented | 24 | // Assuming RGBA8 format until actual framebuffer format handling is implemented |
| @@ -26,14 +26,14 @@ static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { | |||
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | static u32 GetDepth(int x, int y) { | 28 | static u32 GetDepth(int x, int y) { |
| 29 | u16* depth_buffer = (u16*)Memory::GetPointer(registers.framebuffer.GetDepthBufferAddress()); | 29 | u16* depth_buffer = reinterpret_cast<u16*>(Memory::GetPointer(PAddrToVAddr(registers.framebuffer.GetDepthBufferPhysicalAddress()))); |
| 30 | 30 | ||
| 31 | // Assuming 16-bit depth buffer format until actual format handling is implemented | 31 | // Assuming 16-bit depth buffer format until actual format handling is implemented |
| 32 | return *(depth_buffer + x + y * registers.framebuffer.GetWidth()); | 32 | return *(depth_buffer + x + y * registers.framebuffer.GetWidth()); |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | static void SetDepth(int x, int y, u16 value) { | 35 | static void SetDepth(int x, int y, u16 value) { |
| 36 | u16* depth_buffer = (u16*)Memory::GetPointer(registers.framebuffer.GetDepthBufferAddress()); | 36 | u16* depth_buffer = reinterpret_cast<u16*>(Memory::GetPointer(PAddrToVAddr(registers.framebuffer.GetDepthBufferPhysicalAddress()))); |
| 37 | 37 | ||
| 38 | // Assuming 16-bit depth buffer format until actual format handling is implemented | 38 | // Assuming 16-bit depth buffer format until actual format handling is implemented |
| 39 | *(depth_buffer + x + y * registers.framebuffer.GetWidth()) = value; | 39 | *(depth_buffer + x + y * registers.framebuffer.GetWidth()) = value; |
| @@ -167,60 +167,48 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, | |||
| 167 | (u8)(GetInterpolatedAttribute(v0.color.a(), v1.color.a(), v2.color.a()).ToFloat32() * 255) | 167 | (u8)(GetInterpolatedAttribute(v0.color.a(), v1.color.a(), v2.color.a()).ToFloat32() * 255) |
| 168 | }; | 168 | }; |
| 169 | 169 | ||
| 170 | Math::Vec4<u8> texture_color{}; | 170 | Math::Vec2<float24> uv[3]; |
| 171 | float24 u = GetInterpolatedAttribute(v0.tc0.u(), v1.tc0.u(), v2.tc0.u()); | 171 | uv[0].u() = GetInterpolatedAttribute(v0.tc0.u(), v1.tc0.u(), v2.tc0.u()); |
| 172 | float24 v = GetInterpolatedAttribute(v0.tc0.v(), v1.tc0.v(), v2.tc0.v()); | 172 | uv[0].v() = GetInterpolatedAttribute(v0.tc0.v(), v1.tc0.v(), v2.tc0.v()); |
| 173 | if (registers.texturing_enable) { | 173 | uv[1].u() = GetInterpolatedAttribute(v0.tc1.u(), v1.tc1.u(), v2.tc1.u()); |
| 174 | // Images are split into 8x8 tiles. Each tile is composed of four 4x4 subtiles each | 174 | uv[1].v() = GetInterpolatedAttribute(v0.tc1.v(), v1.tc1.v(), v2.tc1.v()); |
| 175 | // of which is composed of four 2x2 subtiles each of which is composed of four texels. | 175 | uv[2].u() = GetInterpolatedAttribute(v0.tc2.u(), v1.tc2.u(), v2.tc2.u()); |
| 176 | // Each structure is embedded into the next-bigger one in a diagonal pattern, e.g. | 176 | uv[2].v() = GetInterpolatedAttribute(v0.tc2.v(), v1.tc2.v(), v2.tc2.v()); |
| 177 | // texels are laid out in a 2x2 subtile like this: | 177 | |
| 178 | // 2 3 | 178 | Math::Vec4<u8> texture_color[3]{}; |
| 179 | // 0 1 | 179 | for (int i = 0; i < 3; ++i) { |
| 180 | // | 180 | auto texture = registers.GetTextures()[i]; |
| 181 | // The full 8x8 tile has the texels arranged like this: | 181 | if (!texture.enabled) |
| 182 | // | 182 | continue; |
| 183 | // 42 43 46 47 58 59 62 63 | 183 | |
| 184 | // 40 41 44 45 56 57 60 61 | 184 | _dbg_assert_(HW_GPU, 0 != texture.config.address); |
| 185 | // 34 35 38 39 50 51 54 55 | 185 | |
| 186 | // 32 33 36 37 48 49 52 53 | 186 | int s = (int)(uv[i].u() * float24::FromFloat32(static_cast<float>(texture.config.width))).ToFloat32(); |
| 187 | // 10 11 14 15 26 27 30 31 | 187 | int t = (int)(uv[i].v() * float24::FromFloat32(static_cast<float>(texture.config.height))).ToFloat32(); |
| 188 | // 08 09 12 13 24 25 28 29 | 188 | auto GetWrappedTexCoord = [](Regs::TextureConfig::WrapMode mode, int val, unsigned size) { |
| 189 | // 02 03 06 07 18 19 22 23 | 189 | switch (mode) { |
| 190 | // 00 01 04 05 16 17 20 21 | 190 | case Regs::TextureConfig::ClampToEdge: |
| 191 | 191 | val = std::max(val, 0); | |
| 192 | // TODO: This is currently hardcoded for RGB8 | 192 | val = std::min(val, (int)size - 1); |
| 193 | u32* texture_data = (u32*)Memory::GetPointer(registers.texture0.GetPhysicalAddress()); | 193 | return val; |
| 194 | 194 | ||
| 195 | // TODO(neobrain): Not sure if this swizzling pattern is used for all textures. | 195 | case Regs::TextureConfig::Repeat: |
| 196 | // To be flexible in case different but similar patterns are used, we keep this | 196 | return (int)(((unsigned)val) % size); |
| 197 | // somewhat inefficient code around for now. | 197 | |
| 198 | int s = (int)(u * float24::FromFloat32(static_cast<float>(registers.texture0.width))).ToFloat32(); | 198 | default: |
| 199 | int t = (int)(v * float24::FromFloat32(static_cast<float>(registers.texture0.height))).ToFloat32(); | 199 | LOG_ERROR(HW_GPU, "Unknown texture coordinate wrapping mode %x\n", (int)mode); |
| 200 | int texel_index_within_tile = 0; | 200 | _dbg_assert_(HW_GPU, 0); |
| 201 | for (int block_size_index = 0; block_size_index < 3; ++block_size_index) { | 201 | return 0; |
| 202 | int sub_tile_width = 1 << block_size_index; | 202 | } |
| 203 | int sub_tile_height = 1 << block_size_index; | 203 | }; |
| 204 | 204 | s = GetWrappedTexCoord(registers.texture0.wrap_s, s, registers.texture0.width); | |
| 205 | int sub_tile_index = (s & sub_tile_width) << block_size_index; | 205 | t = GetWrappedTexCoord(registers.texture0.wrap_t, t, registers.texture0.height); |
| 206 | sub_tile_index += 2 * ((t & sub_tile_height) << block_size_index); | 206 | |
| 207 | texel_index_within_tile += sub_tile_index; | 207 | u8* texture_data = Memory::GetPointer(PAddrToVAddr(texture.config.GetPhysicalAddress())); |
| 208 | } | 208 | auto info = DebugUtils::TextureInfo::FromPicaRegister(texture.config, texture.format); |
| 209 | 209 | ||
| 210 | const int block_width = 8; | 210 | texture_color[i] = DebugUtils::LookupTexture(texture_data, s, t, info); |
| 211 | const int block_height = 8; | 211 | DebugUtils::DumpTexture(texture.config, texture_data); |
| 212 | |||
| 213 | int coarse_s = (s / block_width) * block_width; | ||
| 214 | int coarse_t = (t / block_height) * block_height; | ||
| 215 | |||
| 216 | const int row_stride = registers.texture0.width * 3; | ||
| 217 | u8* source_ptr = (u8*)texture_data + coarse_s * block_height * 3 + coarse_t * row_stride + texel_index_within_tile * 3; | ||
| 218 | texture_color.r() = source_ptr[2]; | ||
| 219 | texture_color.g() = source_ptr[1]; | ||
| 220 | texture_color.b() = source_ptr[0]; | ||
| 221 | texture_color.a() = 0xFF; | ||
| 222 | |||
| 223 | DebugUtils::DumpTexture(registers.texture0, (u8*)texture_data); | ||
| 224 | } | 212 | } |
| 225 | 213 | ||
| 226 | // Texture environment - consists of 6 stages of color and alpha combining. | 214 | // Texture environment - consists of 6 stages of color and alpha combining. |
| @@ -237,22 +225,29 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, | |||
| 237 | using AlphaModifier = Regs::TevStageConfig::AlphaModifier; | 225 | using AlphaModifier = Regs::TevStageConfig::AlphaModifier; |
| 238 | using Operation = Regs::TevStageConfig::Operation; | 226 | using Operation = Regs::TevStageConfig::Operation; |
| 239 | 227 | ||
| 240 | auto GetColorSource = [&](Source source) -> Math::Vec3<u8> { | 228 | auto GetColorSource = [&](Source source) -> Math::Vec4<u8> { |
| 241 | switch (source) { | 229 | switch (source) { |
| 242 | case Source::PrimaryColor: | 230 | case Source::PrimaryColor: |
| 243 | return primary_color.rgb(); | 231 | return primary_color; |
| 244 | 232 | ||
| 245 | case Source::Texture0: | 233 | case Source::Texture0: |
| 246 | return texture_color.rgb(); | 234 | return texture_color[0]; |
| 235 | |||
| 236 | case Source::Texture1: | ||
| 237 | return texture_color[1]; | ||
| 238 | |||
| 239 | case Source::Texture2: | ||
| 240 | return texture_color[2]; | ||
| 247 | 241 | ||
| 248 | case Source::Constant: | 242 | case Source::Constant: |
| 249 | return {tev_stage.const_r, tev_stage.const_g, tev_stage.const_b}; | 243 | return {tev_stage.const_r, tev_stage.const_g, tev_stage.const_b, tev_stage.const_a}; |
| 250 | 244 | ||
| 251 | case Source::Previous: | 245 | case Source::Previous: |
| 252 | return combiner_output.rgb(); | 246 | return combiner_output; |
| 253 | 247 | ||
| 254 | default: | 248 | default: |
| 255 | LOG_ERROR(HW_GPU, "Unknown color combiner source %d\n", (int)source); | 249 | LOG_ERROR(HW_GPU, "Unknown color combiner source %d\n", (int)source); |
| 250 | _dbg_assert_(HW_GPU, 0); | ||
| 256 | return {}; | 251 | return {}; |
| 257 | } | 252 | } |
| 258 | }; | 253 | }; |
| @@ -263,7 +258,13 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, | |||
| 263 | return primary_color.a(); | 258 | return primary_color.a(); |
| 264 | 259 | ||
| 265 | case Source::Texture0: | 260 | case Source::Texture0: |
| 266 | return texture_color.a(); | 261 | return texture_color[0].a(); |
| 262 | |||
| 263 | case Source::Texture1: | ||
| 264 | return texture_color[1].a(); | ||
| 265 | |||
| 266 | case Source::Texture2: | ||
| 267 | return texture_color[2].a(); | ||
| 267 | 268 | ||
| 268 | case Source::Constant: | 269 | case Source::Constant: |
| 269 | return tev_stage.const_a; | 270 | return tev_stage.const_a; |
| @@ -273,17 +274,23 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, | |||
| 273 | 274 | ||
| 274 | default: | 275 | default: |
| 275 | LOG_ERROR(HW_GPU, "Unknown alpha combiner source %d\n", (int)source); | 276 | LOG_ERROR(HW_GPU, "Unknown alpha combiner source %d\n", (int)source); |
| 277 | _dbg_assert_(HW_GPU, 0); | ||
| 276 | return 0; | 278 | return 0; |
| 277 | } | 279 | } |
| 278 | }; | 280 | }; |
| 279 | 281 | ||
| 280 | auto GetColorModifier = [](ColorModifier factor, const Math::Vec3<u8>& values) -> Math::Vec3<u8> { | 282 | auto GetColorModifier = [](ColorModifier factor, const Math::Vec4<u8>& values) -> Math::Vec3<u8> { |
| 281 | switch (factor) | 283 | switch (factor) |
| 282 | { | 284 | { |
| 283 | case ColorModifier::SourceColor: | 285 | case ColorModifier::SourceColor: |
| 284 | return values; | 286 | return values.rgb(); |
| 287 | |||
| 288 | case ColorModifier::SourceAlpha: | ||
| 289 | return { values.a(), values.a(), values.a() }; | ||
| 290 | |||
| 285 | default: | 291 | default: |
| 286 | LOG_ERROR(HW_GPU, "Unknown color factor %d\n", (int)factor); | 292 | LOG_ERROR(HW_GPU, "Unknown color factor %d\n", (int)factor); |
| 293 | _dbg_assert_(HW_GPU, 0); | ||
| 287 | return {}; | 294 | return {}; |
| 288 | } | 295 | } |
| 289 | }; | 296 | }; |
| @@ -292,8 +299,13 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, | |||
| 292 | switch (factor) { | 299 | switch (factor) { |
| 293 | case AlphaModifier::SourceAlpha: | 300 | case AlphaModifier::SourceAlpha: |
| 294 | return value; | 301 | return value; |
| 302 | |||
| 303 | case AlphaModifier::OneMinusSourceAlpha: | ||
| 304 | return 255 - value; | ||
| 305 | |||
| 295 | default: | 306 | default: |
| 296 | LOG_ERROR(HW_GPU, "Unknown color factor %d\n", (int)factor); | 307 | LOG_ERROR(HW_GPU, "Unknown alpha factor %d\n", (int)factor); |
| 308 | _dbg_assert_(HW_GPU, 0); | ||
| 297 | return 0; | 309 | return 0; |
| 298 | } | 310 | } |
| 299 | }; | 311 | }; |
| @@ -306,8 +318,21 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, | |||
| 306 | case Operation::Modulate: | 318 | case Operation::Modulate: |
| 307 | return ((input[0] * input[1]) / 255).Cast<u8>(); | 319 | return ((input[0] * input[1]) / 255).Cast<u8>(); |
| 308 | 320 | ||
| 321 | case Operation::Add: | ||
| 322 | { | ||
| 323 | auto result = input[0] + input[1]; | ||
| 324 | result.r() = std::min(255, result.r()); | ||
| 325 | result.g() = std::min(255, result.g()); | ||
| 326 | result.b() = std::min(255, result.b()); | ||
| 327 | return result.Cast<u8>(); | ||
| 328 | } | ||
| 329 | |||
| 330 | case Operation::Lerp: | ||
| 331 | return ((input[0] * input[2] + input[1] * (Math::MakeVec<u8>(255, 255, 255) - input[2]).Cast<u8>()) / 255).Cast<u8>(); | ||
| 332 | |||
| 309 | default: | 333 | default: |
| 310 | LOG_ERROR(HW_GPU, "Unknown color combiner operation %d\n", (int)op); | 334 | LOG_ERROR(HW_GPU, "Unknown color combiner operation %d\n", (int)op); |
| 335 | _dbg_assert_(HW_GPU, 0); | ||
| 311 | return {}; | 336 | return {}; |
| 312 | } | 337 | } |
| 313 | }; | 338 | }; |
| @@ -320,8 +345,15 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, | |||
| 320 | case Operation::Modulate: | 345 | case Operation::Modulate: |
| 321 | return input[0] * input[1] / 255; | 346 | return input[0] * input[1] / 255; |
| 322 | 347 | ||
| 348 | case Operation::Add: | ||
| 349 | return std::min(255, input[0] + input[1]); | ||
| 350 | |||
| 351 | case Operation::Lerp: | ||
| 352 | return (input[0] * input[2] + input[1] * (255 - input[2])) / 255; | ||
| 353 | |||
| 323 | default: | 354 | default: |
| 324 | LOG_ERROR(HW_GPU, "Unknown alpha combiner operation %d\n", (int)op); | 355 | LOG_ERROR(HW_GPU, "Unknown alpha combiner operation %d\n", (int)op); |
| 356 | _dbg_assert_(HW_GPU, 0); | ||
| 325 | return 0; | 357 | return 0; |
| 326 | } | 358 | } |
| 327 | }; | 359 | }; |