trunk/src/osd/modules/render/d3d/d3dhlsl.c
| r250287 | r250288 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Aaron Giles |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // d3dhlsl.c - Win32 Direct3D HLSL implementation |
| 6 | | // |
| 7 | | //============================================================ |
| 8 | | |
| 9 | | // Useful info: |
| 10 | | // Windows XP/2003 shipped with DirectX 8.1 |
| 11 | | // Windows 2000 shipped with DirectX 7a |
| 12 | | // Windows 98SE shipped with DirectX 6.1a |
| 13 | | // Windows 98 shipped with DirectX 5 |
| 14 | | // Windows NT shipped with DirectX 3.0a |
| 15 | | // Windows 95 shipped with DirectX 2 |
| 16 | | |
| 17 | | // standard windows headers |
| 18 | | #define WIN32_LEAN_AND_MEAN |
| 19 | | #include <windows.h> |
| 20 | | #include <tchar.h> |
| 21 | | #include <mmsystem.h> |
| 22 | | #include <d3d9.h> |
| 23 | | #include <d3dx9.h> |
| 24 | | #include <math.h> |
| 25 | | #undef interface |
| 26 | | |
| 27 | | // MAME headers |
| 28 | | #include "emu.h" |
| 29 | | #include "render.h" |
| 30 | | #include "ui/ui.h" |
| 31 | | #include "rendutil.h" |
| 32 | | #include "options.h" |
| 33 | | #include "emuopts.h" |
| 34 | | #include "aviio.h" |
| 35 | | #include "png.h" |
| 36 | | #include "screen.h" |
| 37 | | |
| 38 | | // MAMEOS headers |
| 39 | | #include "d3dintf.h" |
| 40 | | #include "winmain.h" |
| 41 | | #include "window.h" |
| 42 | | #include "config.h" |
| 43 | | #include "d3dcomm.h" |
| 44 | | #include "modules/render/drawd3d.h" |
| 45 | | #include "strconv.h" |
| 46 | | |
| 47 | | |
| 48 | | //============================================================ |
| 49 | | // GLOBALS |
| 50 | | //============================================================ |
| 51 | | |
| 52 | | static slider_state *g_slider_list; |
| 53 | | static file_error open_next(d3d::renderer *d3d, emu_file &file, const char *templ, const char *extension, int idx); |
| 54 | | |
| 55 | | namespace d3d |
| 56 | | { |
| 57 | | |
| 58 | | //============================================================ |
| 59 | | // PROTOTYPES |
| 60 | | //============================================================ |
| 61 | | |
| 62 | | static void get_vector(const char *data, int count, float *out, bool report_error); |
| 63 | | |
| 64 | | |
| 65 | | //============================================================ |
| 66 | | // TYPE DEFINITIONS |
| 67 | | //============================================================ |
| 68 | | |
| 69 | | typedef HRESULT (WINAPI *direct3dx9_loadeffect_ptr)(LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, const D3DXMACRO *pDefines, LPD3DXINCLUDE pInclude, DWORD Flags, LPD3DXEFFECTPOOL pPool, LPD3DXEFFECT *ppEffect, LPD3DXBUFFER *ppCompilationErrors); |
| 70 | | static direct3dx9_loadeffect_ptr g_load_effect = NULL; |
| 71 | | |
| 72 | | |
| 73 | | //============================================================ |
| 74 | | // shader manager constructor |
| 75 | | //============================================================ |
| 76 | | |
| 77 | | shaders::shaders() |
| 78 | | { |
| 79 | | master_enable = false; |
| 80 | | vector_enable = true; |
| 81 | | hlsl_prescale_x = 1; |
| 82 | | hlsl_prescale_x = 1; |
| 83 | | preset = -1; |
| 84 | | shadow_texture = NULL; |
| 85 | | options = NULL; |
| 86 | | paused = true; |
| 87 | | lastidx = -1; |
| 88 | | targethead = NULL; |
| 89 | | cachehead = NULL; |
| 90 | | initialized = false; |
| 91 | | } |
| 92 | | |
| 93 | | |
| 94 | | //============================================================ |
| 95 | | // shaders destructor |
| 96 | | //============================================================ |
| 97 | | |
| 98 | | shaders::~shaders() |
| 99 | | { |
| 100 | | cache_target *currcache = cachehead; |
| 101 | | while(cachehead != NULL) |
| 102 | | { |
| 103 | | cachehead = currcache->next; |
| 104 | | global_free(currcache); |
| 105 | | currcache = cachehead; |
| 106 | | } |
| 107 | | |
| 108 | | render_target *currtarget = targethead; |
| 109 | | while(targethead != NULL) |
| 110 | | { |
| 111 | | targethead = currtarget->next; |
| 112 | | global_free(currtarget); |
| 113 | | currtarget = targethead; |
| 114 | | } |
| 115 | | } |
| 116 | | |
| 117 | | |
| 118 | | //============================================================ |
| 119 | | // shaders::window_save |
| 120 | | //============================================================ |
| 121 | | |
| 122 | | void shaders::window_save() |
| 123 | | { |
| 124 | | if (!master_enable || !d3dintf->post_fx_available) |
| 125 | | { |
| 126 | | return; |
| 127 | | } |
| 128 | | |
| 129 | | HRESULT result = (*d3dintf->device.create_texture)(d3d->get_device(), snap_width, snap_height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &snap_copy_texture); |
| 130 | | if (result != D3D_OK) |
| 131 | | { |
| 132 | | osd_printf_verbose("Direct3D: Unable to init system-memory target for HLSL snapshot (%08x), bailing\n", (UINT32)result); |
| 133 | | return; |
| 134 | | } |
| 135 | | (*d3dintf->texture.get_surface_level)(snap_copy_texture, 0, &snap_copy_target); |
| 136 | | |
| 137 | | result = (*d3dintf->device.create_texture)(d3d->get_device(), snap_width, snap_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &snap_texture); |
| 138 | | if (result != D3D_OK) |
| 139 | | { |
| 140 | | osd_printf_verbose("Direct3D: Unable to init video-memory target for HLSL snapshot (%08x), bailing\n", (UINT32)result); |
| 141 | | return; |
| 142 | | } |
| 143 | | (*d3dintf->texture.get_surface_level)(snap_texture, 0, &snap_target); |
| 144 | | |
| 145 | | render_snap = true; |
| 146 | | snap_rendered = false; |
| 147 | | } |
| 148 | | |
| 149 | | |
| 150 | | //============================================================ |
| 151 | | // shaders::window_record |
| 152 | | //============================================================ |
| 153 | | |
| 154 | | void shaders::window_record() |
| 155 | | { |
| 156 | | if (!master_enable || !d3dintf->post_fx_available) |
| 157 | | { |
| 158 | | return; |
| 159 | | } |
| 160 | | |
| 161 | | windows_options &options = downcast<windows_options &>(machine->options()); |
| 162 | | const char *filename = options.d3d_hlsl_write(); |
| 163 | | |
| 164 | | if (avi_output_file != NULL) |
| 165 | | { |
| 166 | | end_avi_recording(); |
| 167 | | } |
| 168 | | else if (filename[0] != 0) |
| 169 | | { |
| 170 | | begin_avi_recording(filename); |
| 171 | | } |
| 172 | | } |
| 173 | | |
| 174 | | |
| 175 | | //============================================================ |
| 176 | | // shaders::avi_update_snap |
| 177 | | //============================================================ |
| 178 | | |
| 179 | | void shaders::avi_update_snap(surface *surface) |
| 180 | | { |
| 181 | | if (!master_enable || !d3dintf->post_fx_available) |
| 182 | | { |
| 183 | | return; |
| 184 | | } |
| 185 | | |
| 186 | | D3DLOCKED_RECT rect; |
| 187 | | |
| 188 | | // if we don't have a bitmap, or if it's not the right size, allocate a new one |
| 189 | | if (!avi_snap.valid() || (int)snap_width != avi_snap.width() || (int)snap_height != avi_snap.height()) |
| 190 | | { |
| 191 | | avi_snap.allocate((int)snap_width, (int)snap_height); |
| 192 | | } |
| 193 | | |
| 194 | | // copy the texture |
| 195 | | HRESULT result = (*d3dintf->device.get_render_target_data)(d3d->get_device(), surface, avi_copy_surface); |
| 196 | | if (result != D3D_OK) |
| 197 | | { |
| 198 | | return; |
| 199 | | } |
| 200 | | |
| 201 | | // lock the texture |
| 202 | | result = (*d3dintf->surface.lock_rect)(avi_copy_surface, &rect, NULL, D3DLOCK_DISCARD); |
| 203 | | if (result != D3D_OK) |
| 204 | | { |
| 205 | | return; |
| 206 | | } |
| 207 | | |
| 208 | | // loop over Y |
| 209 | | for (int srcy = 0; srcy < (int)snap_height; srcy++) |
| 210 | | { |
| 211 | | DWORD *src = (DWORD *)((BYTE *)rect.pBits + srcy * rect.Pitch); |
| 212 | | UINT32 *dst = &avi_snap.pix32(srcy); |
| 213 | | |
| 214 | | for (int x = 0; x < snap_width; x++) |
| 215 | | { |
| 216 | | *dst++ = *src++; |
| 217 | | } |
| 218 | | } |
| 219 | | |
| 220 | | // unlock |
| 221 | | result = (*d3dintf->surface.unlock_rect)(avi_copy_surface); |
| 222 | | if (result != D3D_OK) |
| 223 | | { |
| 224 | | osd_printf_verbose("Direct3D: Error %08X during texture unlock_rect call\n", (int)result); |
| 225 | | } |
| 226 | | } |
| 227 | | |
| 228 | | |
| 229 | | |
| 230 | | //============================================================ |
| 231 | | // hlsl_render_snapshot |
| 232 | | //============================================================ |
| 233 | | |
| 234 | | void shaders::render_snapshot(surface *surface) |
| 235 | | { |
| 236 | | if (!master_enable || !d3dintf->post_fx_available) |
| 237 | | { |
| 238 | | return; |
| 239 | | } |
| 240 | | |
| 241 | | D3DLOCKED_RECT rect; |
| 242 | | |
| 243 | | render_snap = false; |
| 244 | | |
| 245 | | // if we don't have a bitmap, or if it's not the right size, allocate a new one |
| 246 | | if (!avi_snap.valid() || snap_width != (avi_snap.width() / 2) || snap_height != (avi_snap.height() / 2)) |
| 247 | | { |
| 248 | | avi_snap.allocate(snap_width / 2, snap_height / 2); |
| 249 | | } |
| 250 | | |
| 251 | | // copy the texture |
| 252 | | HRESULT result = (*d3dintf->device.get_render_target_data)(d3d->get_device(), surface, snap_copy_target); |
| 253 | | if (result != D3D_OK) |
| 254 | | { |
| 255 | | return; |
| 256 | | } |
| 257 | | |
| 258 | | // lock the texture |
| 259 | | result = (*d3dintf->surface.lock_rect)(snap_copy_target, &rect, NULL, D3DLOCK_DISCARD); |
| 260 | | if (result != D3D_OK) |
| 261 | | { |
| 262 | | return; |
| 263 | | } |
| 264 | | |
| 265 | | for (int cy = 0; cy < 2; cy++) |
| 266 | | { |
| 267 | | for (int cx = 0; cx < 2; cx++) |
| 268 | | { |
| 269 | | // loop over Y |
| 270 | | for (int srcy = 0; srcy < snap_height / 2; srcy++) |
| 271 | | { |
| 272 | | int toty = (srcy + cy * (snap_height / 2)); |
| 273 | | int totx = cx * (snap_width / 2); |
| 274 | | DWORD *src = (DWORD *)((BYTE *)rect.pBits + toty * rect.Pitch + totx * 4); |
| 275 | | UINT32 *dst = &avi_snap.pix32(srcy); |
| 276 | | |
| 277 | | for (int x = 0; x < snap_width / 2; x++) |
| 278 | | { |
| 279 | | *dst++ = *src++; |
| 280 | | } |
| 281 | | } |
| 282 | | |
| 283 | | int idx = cy * 2 + cx; |
| 284 | | |
| 285 | | emu_file file(machine->options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); |
| 286 | | file_error filerr = open_next(d3d, file, NULL, "png", idx); |
| 287 | | if (filerr != FILERR_NONE) |
| 288 | | { |
| 289 | | return; |
| 290 | | } |
| 291 | | |
| 292 | | // add two text entries describing the image |
| 293 | | std::string text1 = std::string(emulator_info::get_appname()).append(" ").append(build_version); |
| 294 | | std::string text2 = std::string(machine->system().manufacturer).append(" ").append(machine->system().description); |
| 295 | | png_info pnginfo = { 0 }; |
| 296 | | png_add_text(&pnginfo, "Software", text1.c_str()); |
| 297 | | png_add_text(&pnginfo, "System", text2.c_str()); |
| 298 | | |
| 299 | | // now do the actual work |
| 300 | | png_error error = png_write_bitmap(file, &pnginfo, avi_snap, 1 << 24, NULL); |
| 301 | | if (error != PNGERR_NONE) |
| 302 | | { |
| 303 | | osd_printf_error("Error generating PNG for HLSL snapshot: png_error = %d\n", error); |
| 304 | | } |
| 305 | | |
| 306 | | // free any data allocated |
| 307 | | png_free(&pnginfo); |
| 308 | | } |
| 309 | | } |
| 310 | | |
| 311 | | // unlock |
| 312 | | result = (*d3dintf->surface.unlock_rect)(snap_copy_target); |
| 313 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during texture unlock_rect call\n", (int)result); |
| 314 | | |
| 315 | | if (snap_texture != NULL) |
| 316 | | { |
| 317 | | (*d3dintf->texture.release)(snap_texture); |
| 318 | | snap_texture = NULL; |
| 319 | | } |
| 320 | | |
| 321 | | if (snap_target != NULL) |
| 322 | | { |
| 323 | | (*d3dintf->surface.release)(snap_target); |
| 324 | | snap_target = NULL; |
| 325 | | } |
| 326 | | |
| 327 | | if (snap_copy_texture != NULL) |
| 328 | | { |
| 329 | | (*d3dintf->texture.release)(snap_copy_texture); |
| 330 | | snap_copy_texture = NULL; |
| 331 | | } |
| 332 | | |
| 333 | | if (snap_copy_target != NULL) |
| 334 | | { |
| 335 | | (*d3dintf->surface.release)(snap_copy_target); |
| 336 | | snap_copy_target = NULL; |
| 337 | | } |
| 338 | | } |
| 339 | | |
| 340 | | |
| 341 | | //============================================================ |
| 342 | | // shaders::record_texture |
| 343 | | //============================================================ |
| 344 | | |
| 345 | | void shaders::record_texture() |
| 346 | | { |
| 347 | | if (!master_enable || !d3dintf->post_fx_available) |
| 348 | | { |
| 349 | | return; |
| 350 | | } |
| 351 | | |
| 352 | | surface *surface = avi_final_target; |
| 353 | | |
| 354 | | // ignore if nothing to do |
| 355 | | if (avi_output_file == NULL || surface == NULL) |
| 356 | | { |
| 357 | | return; |
| 358 | | } |
| 359 | | |
| 360 | | // get the current time |
| 361 | | attotime curtime = machine->time(); |
| 362 | | |
| 363 | | avi_update_snap(surface); |
| 364 | | |
| 365 | | // loop until we hit the right time |
| 366 | | while (avi_next_frame_time <= curtime) |
| 367 | | { |
| 368 | | // handle an AVI recording |
| 369 | | // write the next frame |
| 370 | | avi_error avierr = avi_append_video_frame(avi_output_file, avi_snap); |
| 371 | | if (avierr != AVIERR_NONE) |
| 372 | | { |
| 373 | | end_avi_recording(); |
| 374 | | return; |
| 375 | | } |
| 376 | | |
| 377 | | // advance time |
| 378 | | avi_next_frame_time += avi_frame_period; |
| 379 | | avi_frame++; |
| 380 | | } |
| 381 | | } |
| 382 | | |
| 383 | | |
| 384 | | //============================================================ |
| 385 | | // shaders::end_hlsl_avi_recording |
| 386 | | //============================================================ |
| 387 | | |
| 388 | | void shaders::end_avi_recording() |
| 389 | | { |
| 390 | | if (!master_enable || !d3dintf->post_fx_available) |
| 391 | | { |
| 392 | | return; |
| 393 | | } |
| 394 | | |
| 395 | | if (avi_output_file != NULL) |
| 396 | | { |
| 397 | | avi_close(avi_output_file); |
| 398 | | } |
| 399 | | |
| 400 | | avi_output_file = NULL; |
| 401 | | avi_frame = 0; |
| 402 | | } |
| 403 | | |
| 404 | | |
| 405 | | //============================================================ |
| 406 | | // shaders::toggle |
| 407 | | //============================================================ |
| 408 | | |
| 409 | | void shaders::toggle() |
| 410 | | { |
| 411 | | if (master_enable) |
| 412 | | { |
| 413 | | if (initialized) |
| 414 | | { |
| 415 | | delete_resources(false); |
| 416 | | } |
| 417 | | master_enable = !master_enable; |
| 418 | | } |
| 419 | | else |
| 420 | | { |
| 421 | | if (!initialized) |
| 422 | | { |
| 423 | | master_enable = !master_enable; |
| 424 | | bool failed = create_resources(false); |
| 425 | | if (failed) |
| 426 | | { |
| 427 | | master_enable = false; |
| 428 | | } |
| 429 | | } |
| 430 | | else |
| 431 | | { |
| 432 | | master_enable = !master_enable; |
| 433 | | } |
| 434 | | } |
| 435 | | } |
| 436 | | |
| 437 | | //============================================================ |
| 438 | | // shaders::begin_avi_recording |
| 439 | | //============================================================ |
| 440 | | |
| 441 | | void shaders::begin_avi_recording(const char *name) |
| 442 | | { |
| 443 | | if (!master_enable || !d3dintf->post_fx_available) |
| 444 | | { |
| 445 | | return; |
| 446 | | } |
| 447 | | |
| 448 | | // stop any existing recording |
| 449 | | end_avi_recording(); |
| 450 | | |
| 451 | | // reset the state |
| 452 | | avi_frame = 0; |
| 453 | | avi_next_frame_time = machine->time(); |
| 454 | | |
| 455 | | // build up information about this new movie |
| 456 | | avi_movie_info info; |
| 457 | | info.video_format = 0; |
| 458 | | info.video_timescale = 1000 * ((machine->first_screen() != NULL) ? ATTOSECONDS_TO_HZ(machine->first_screen()->frame_period().m_attoseconds) : screen_device::DEFAULT_FRAME_RATE); |
| 459 | | info.video_sampletime = 1000; |
| 460 | | info.video_numsamples = 0; |
| 461 | | info.video_width = snap_width; |
| 462 | | info.video_height = snap_height; |
| 463 | | info.video_depth = 24; |
| 464 | | |
| 465 | | info.audio_format = 0; |
| 466 | | info.audio_timescale = machine->sample_rate(); |
| 467 | | info.audio_sampletime = 1; |
| 468 | | info.audio_numsamples = 0; |
| 469 | | info.audio_channels = 2; |
| 470 | | info.audio_samplebits = 16; |
| 471 | | info.audio_samplerate = machine->sample_rate(); |
| 472 | | |
| 473 | | // create a new temporary movie file |
| 474 | | file_error filerr; |
| 475 | | std::string fullpath; |
| 476 | | { |
| 477 | | emu_file tempfile(machine->options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); |
| 478 | | if (name != NULL) |
| 479 | | { |
| 480 | | filerr = tempfile.open(name); |
| 481 | | } |
| 482 | | else |
| 483 | | { |
| 484 | | filerr = open_next(d3d, tempfile, NULL, "avi", 0); |
| 485 | | } |
| 486 | | |
| 487 | | // compute the frame time |
| 488 | | { |
| 489 | | avi_frame_period = attotime::from_seconds(1000) / info.video_timescale; |
| 490 | | } |
| 491 | | |
| 492 | | // if we succeeded, make a copy of the name and create the real file over top |
| 493 | | if (filerr == FILERR_NONE) |
| 494 | | { |
| 495 | | fullpath = tempfile.fullpath(); |
| 496 | | } |
| 497 | | } |
| 498 | | |
| 499 | | if (filerr == FILERR_NONE) |
| 500 | | { |
| 501 | | // create the file and free the string |
| 502 | | avi_error avierr = avi_create(fullpath.c_str(), &info, &avi_output_file); |
| 503 | | if (avierr != AVIERR_NONE) |
| 504 | | { |
| 505 | | osd_printf_error("Error creating AVI: %s\n", avi_error_string(avierr)); |
| 506 | | } |
| 507 | | } |
| 508 | | } |
| 509 | | |
| 510 | | |
| 511 | | //============================================================ |
| 512 | | // remove_cache_target - remove an active cache target when |
| 513 | | // refcount hits zero |
| 514 | | //============================================================ |
| 515 | | |
| 516 | | void shaders::remove_cache_target(cache_target *cache) |
| 517 | | { |
| 518 | | if (cache != NULL) |
| 519 | | { |
| 520 | | if (cache == cachehead) |
| 521 | | { |
| 522 | | cachehead = cachehead->next; |
| 523 | | } |
| 524 | | |
| 525 | | if (cache->prev != NULL) |
| 526 | | { |
| 527 | | cache->prev->next = cache->next; |
| 528 | | } |
| 529 | | |
| 530 | | if (cache->next != NULL) |
| 531 | | { |
| 532 | | cache->next->prev = cache->prev; |
| 533 | | } |
| 534 | | |
| 535 | | global_free(cache); |
| 536 | | } |
| 537 | | } |
| 538 | | |
| 539 | | |
| 540 | | //============================================================ |
| 541 | | // remove_render_target - remove an active target |
| 542 | | //============================================================ |
| 543 | | |
| 544 | | void shaders::remove_render_target(texture_info *texture) |
| 545 | | { |
| 546 | | remove_render_target(find_render_target(texture)); |
| 547 | | } |
| 548 | | |
| 549 | | void shaders::remove_render_target(int width, int height, UINT32 screen_index, UINT32 page_index) |
| 550 | | { |
| 551 | | render_target *target = find_render_target(width, height, screen_index, page_index); |
| 552 | | if (target != NULL) |
| 553 | | { |
| 554 | | remove_render_target(target); |
| 555 | | } |
| 556 | | } |
| 557 | | |
| 558 | | void shaders::remove_render_target(render_target *rt) |
| 559 | | { |
| 560 | | if (rt != NULL) |
| 561 | | { |
| 562 | | if (rt == targethead) |
| 563 | | { |
| 564 | | targethead = targethead->next; |
| 565 | | } |
| 566 | | |
| 567 | | if (rt->prev != NULL) |
| 568 | | { |
| 569 | | rt->prev->next = rt->next; |
| 570 | | } |
| 571 | | |
| 572 | | if (rt->next != NULL) |
| 573 | | { |
| 574 | | rt->next->prev = rt->prev; |
| 575 | | } |
| 576 | | |
| 577 | | cache_target *cache = find_cache_target(rt->screen_index, rt->width, rt->height); |
| 578 | | if (cache != NULL) |
| 579 | | { |
| 580 | | remove_cache_target(cache); |
| 581 | | } |
| 582 | | |
| 583 | | int screen_index = rt->screen_index; |
| 584 | | int other_page = 1 - rt->page_index; |
| 585 | | int width = rt->width; |
| 586 | | int height = rt->height; |
| 587 | | |
| 588 | | global_free(rt); |
| 589 | | |
| 590 | | // Remove other double-buffered page (if it exists) |
| 591 | | remove_render_target(width, height, screen_index, other_page); |
| 592 | | } |
| 593 | | } |
| 594 | | |
| 595 | | |
| 596 | | //============================================================ |
| 597 | | // shaders::set_texture |
| 598 | | //============================================================ |
| 599 | | |
| 600 | | void shaders::set_texture(texture_info *texture) |
| 601 | | { |
| 602 | | if (!master_enable || !d3dintf->post_fx_available) |
| 603 | | { |
| 604 | | return; |
| 605 | | } |
| 606 | | |
| 607 | | if (texture != NULL) |
| 608 | | { |
| 609 | | paused = texture->paused(); |
| 610 | | texture->advance_frame(); |
| 611 | | } |
| 612 | | |
| 613 | | // set initial texture to use |
| 614 | | texture_info *default_texture = d3d->get_default_texture(); |
| 615 | | default_effect->set_texture("Diffuse", (texture == NULL) ? default_texture->get_finaltex() : texture->get_finaltex()); |
| 616 | | if (options->yiq_enable) |
| 617 | | { |
| 618 | | yiq_encode_effect->set_texture("Diffuse", (texture == NULL) ? default_texture->get_finaltex() : texture->get_finaltex()); |
| 619 | | } |
| 620 | | else |
| 621 | | { |
| 622 | | color_effect->set_texture("Diffuse", (texture == NULL) ? default_texture->get_finaltex() : texture->get_finaltex()); |
| 623 | | } |
| 624 | | } |
| 625 | | |
| 626 | | |
| 627 | | //============================================================ |
| 628 | | // shaders::init |
| 629 | | //============================================================ |
| 630 | | |
| 631 | | void shaders::init(base *d3dintf, running_machine *machine, d3d::renderer *renderer) |
| 632 | | { |
| 633 | | if (!d3dintf->post_fx_available) |
| 634 | | { |
| 635 | | return; |
| 636 | | } |
| 637 | | |
| 638 | | g_load_effect = (direct3dx9_loadeffect_ptr)GetProcAddress(d3dintf->libhandle, "D3DXCreateEffectFromFileW"); |
| 639 | | if (g_load_effect == NULL) |
| 640 | | { |
| 641 | | printf("Direct3D: Unable to find D3DXCreateEffectFromFileW\n"); |
| 642 | | d3dintf->post_fx_available = false; |
| 643 | | return; |
| 644 | | } |
| 645 | | |
| 646 | | this->d3dintf = d3dintf; |
| 647 | | this->machine = machine; |
| 648 | | this->d3d = renderer; |
| 649 | | this->options = renderer->get_shaders_options(); |
| 650 | | |
| 651 | | windows_options &winoptions = downcast<windows_options &>(machine->options()); |
| 652 | | |
| 653 | | master_enable = winoptions.d3d_hlsl_enable(); |
| 654 | | hlsl_prescale_x = winoptions.d3d_hlsl_prescale_x(); |
| 655 | | hlsl_prescale_y = winoptions.d3d_hlsl_prescale_y(); |
| 656 | | snap_width = winoptions.d3d_snap_width(); |
| 657 | | snap_height = winoptions.d3d_snap_height(); |
| 658 | | |
| 659 | | if (!options->params_init) |
| 660 | | { |
| 661 | | strncpy(options->shadow_mask_texture, winoptions.screen_shadow_mask_texture(), sizeof(options->shadow_mask_texture)); |
| 662 | | options->shadow_mask_alpha = winoptions.screen_shadow_mask_alpha(); |
| 663 | | options->shadow_mask_count_x = winoptions.screen_shadow_mask_count_x(); |
| 664 | | options->shadow_mask_count_y = winoptions.screen_shadow_mask_count_y(); |
| 665 | | options->shadow_mask_u_size = winoptions.screen_shadow_mask_u_size(); |
| 666 | | options->shadow_mask_v_size = winoptions.screen_shadow_mask_v_size(); |
| 667 | | options->shadow_mask_u_offset = winoptions.screen_shadow_mask_u_offset(); |
| 668 | | options->shadow_mask_v_offset = winoptions.screen_shadow_mask_v_offset(); |
| 669 | | options->curvature = winoptions.screen_curvature(); |
| 670 | | options->round_corner = winoptions.screen_round_corner(); |
| 671 | | options->smooth_border = winoptions.screen_smooth_border(); |
| 672 | | options->reflection = winoptions.screen_reflection(); |
| 673 | | options->vignetting = winoptions.screen_vignetting(); |
| 674 | | options->scanline_alpha = winoptions.screen_scanline_amount(); |
| 675 | | options->scanline_scale = winoptions.screen_scanline_scale(); |
| 676 | | options->scanline_height = winoptions.screen_scanline_height(); |
| 677 | | options->scanline_bright_scale = winoptions.screen_scanline_bright_scale(); |
| 678 | | options->scanline_bright_offset = winoptions.screen_scanline_bright_offset(); |
| 679 | | options->scanline_offset = winoptions.screen_scanline_offset(); |
| 680 | | get_vector(winoptions.screen_defocus(), 2, options->defocus, TRUE); |
| 681 | | get_vector(winoptions.screen_converge_x(), 3, options->converge_x, TRUE); |
| 682 | | get_vector(winoptions.screen_converge_y(), 3, options->converge_y, TRUE); |
| 683 | | get_vector(winoptions.screen_radial_converge_x(), 3, options->radial_converge_x, TRUE); |
| 684 | | get_vector(winoptions.screen_radial_converge_y(), 3, options->radial_converge_y, TRUE); |
| 685 | | get_vector(winoptions.screen_red_ratio(), 3, options->red_ratio, TRUE); |
| 686 | | get_vector(winoptions.screen_grn_ratio(), 3, options->grn_ratio, TRUE); |
| 687 | | get_vector(winoptions.screen_blu_ratio(), 3, options->blu_ratio, TRUE); |
| 688 | | get_vector(winoptions.screen_offset(), 3, options->offset, TRUE); |
| 689 | | get_vector(winoptions.screen_scale(), 3, options->scale, TRUE); |
| 690 | | get_vector(winoptions.screen_power(), 3, options->power, TRUE); |
| 691 | | get_vector(winoptions.screen_floor(), 3, options->floor, TRUE); |
| 692 | | get_vector(winoptions.screen_phosphor(), 3, options->phosphor, TRUE); |
| 693 | | options->saturation = winoptions.screen_saturation(); |
| 694 | | options->yiq_enable = winoptions.screen_yiq_enable(); |
| 695 | | options->yiq_cc = winoptions.screen_yiq_cc(); |
| 696 | | options->yiq_a = winoptions.screen_yiq_a(); |
| 697 | | options->yiq_b = winoptions.screen_yiq_b(); |
| 698 | | options->yiq_o = winoptions.screen_yiq_o(); |
| 699 | | options->yiq_p = winoptions.screen_yiq_p(); |
| 700 | | options->yiq_n = winoptions.screen_yiq_n(); |
| 701 | | options->yiq_y = winoptions.screen_yiq_y(); |
| 702 | | options->yiq_i = winoptions.screen_yiq_i(); |
| 703 | | options->yiq_q = winoptions.screen_yiq_q(); |
| 704 | | options->yiq_scan_time = winoptions.screen_yiq_scan_time(); |
| 705 | | options->yiq_phase_count = winoptions.screen_yiq_phase_count(); |
| 706 | | options->vector_length_scale = winoptions.screen_vector_length_scale(); |
| 707 | | options->vector_length_ratio = winoptions.screen_vector_length_ratio(); |
| 708 | | options->bloom_scale = winoptions.screen_bloom_scale(); |
| 709 | | get_vector(winoptions.screen_bloom_overdrive(), 3, options->bloom_overdrive, TRUE); |
| 710 | | options->bloom_level0_weight = winoptions.screen_bloom_lvl0_weight(); |
| 711 | | options->bloom_level1_weight = winoptions.screen_bloom_lvl1_weight(); |
| 712 | | options->bloom_level2_weight = winoptions.screen_bloom_lvl2_weight(); |
| 713 | | options->bloom_level3_weight = winoptions.screen_bloom_lvl3_weight(); |
| 714 | | options->bloom_level4_weight = winoptions.screen_bloom_lvl4_weight(); |
| 715 | | options->bloom_level5_weight = winoptions.screen_bloom_lvl5_weight(); |
| 716 | | options->bloom_level6_weight = winoptions.screen_bloom_lvl6_weight(); |
| 717 | | options->bloom_level7_weight = winoptions.screen_bloom_lvl7_weight(); |
| 718 | | options->bloom_level8_weight = winoptions.screen_bloom_lvl8_weight(); |
| 719 | | options->bloom_level9_weight = winoptions.screen_bloom_lvl9_weight(); |
| 720 | | options->bloom_level10_weight = winoptions.screen_bloom_lvl10_weight(); |
| 721 | | |
| 722 | | options->params_init = true; |
| 723 | | } |
| 724 | | |
| 725 | | options->params_dirty = true; |
| 726 | | |
| 727 | | g_slider_list = init_slider_list(); |
| 728 | | } |
| 729 | | |
| 730 | | |
| 731 | | //============================================================ |
| 732 | | // shaders::init_fsfx_quad |
| 733 | | //============================================================ |
| 734 | | |
| 735 | | void shaders::init_fsfx_quad(void *vertbuf) |
| 736 | | { |
| 737 | | // Called at the start of each frame by the D3D code in order to reserve two triangles |
| 738 | | // that are guaranteed to be at a fixed position so as to simply use D3DPT_TRIANGLELIST, 0, 2 |
| 739 | | // instead of having to do bookkeeping about a specific screen quad |
| 740 | | if (!master_enable || !d3dintf->post_fx_available) |
| 741 | | { |
| 742 | | return; |
| 743 | | } |
| 744 | | |
| 745 | | // get a pointer to the vertex buffer |
| 746 | | fsfx_vertices = (vertex *)vertbuf; |
| 747 | | if (fsfx_vertices == NULL) |
| 748 | | { |
| 749 | | return; |
| 750 | | } |
| 751 | | |
| 752 | | // fill in the vertexes clockwise |
| 753 | | fsfx_vertices[0].x = 0.0f; |
| 754 | | fsfx_vertices[0].y = 0.0f; |
| 755 | | fsfx_vertices[1].x = d3d->get_width(); |
| 756 | | fsfx_vertices[1].y = 0.0f; |
| 757 | | fsfx_vertices[2].x = 0.0f; |
| 758 | | fsfx_vertices[2].y = d3d->get_height(); |
| 759 | | fsfx_vertices[3].x = d3d->get_width(); |
| 760 | | fsfx_vertices[3].y = 0.0f; |
| 761 | | fsfx_vertices[4].x = 0.0f; |
| 762 | | fsfx_vertices[4].y = d3d->get_height(); |
| 763 | | fsfx_vertices[5].x = d3d->get_width(); |
| 764 | | fsfx_vertices[5].y = d3d->get_height(); |
| 765 | | |
| 766 | | fsfx_vertices[0].u0 = 0.0f; |
| 767 | | fsfx_vertices[0].v0 = 0.0f; |
| 768 | | |
| 769 | | fsfx_vertices[1].u0 = 1.0f; |
| 770 | | fsfx_vertices[1].v0 = 0.0f; |
| 771 | | |
| 772 | | fsfx_vertices[2].u0 = 0.0f; |
| 773 | | fsfx_vertices[2].v0 = 1.0f; |
| 774 | | |
| 775 | | fsfx_vertices[3].u0 = 1.0f; |
| 776 | | fsfx_vertices[3].v0 = 0.0f; |
| 777 | | |
| 778 | | fsfx_vertices[4].u0 = 0.0f; |
| 779 | | fsfx_vertices[4].v0 = 1.0f; |
| 780 | | |
| 781 | | fsfx_vertices[5].u0 = 1.0f; |
| 782 | | fsfx_vertices[5].v0 = 1.0f; |
| 783 | | |
| 784 | | fsfx_vertices[0].u1 = 0.0f; |
| 785 | | fsfx_vertices[0].v1 = 0.0f; |
| 786 | | fsfx_vertices[1].u1 = 0.0f; |
| 787 | | fsfx_vertices[1].v1 = 0.0f; |
| 788 | | fsfx_vertices[2].u1 = 0.0f; |
| 789 | | fsfx_vertices[2].v1 = 0.0f; |
| 790 | | fsfx_vertices[3].u1 = 0.0f; |
| 791 | | fsfx_vertices[3].v1 = 0.0f; |
| 792 | | fsfx_vertices[4].u1 = 0.0f; |
| 793 | | fsfx_vertices[4].v1 = 0.0f; |
| 794 | | fsfx_vertices[5].u1 = 0.0f; |
| 795 | | fsfx_vertices[5].v1 = 0.0f; |
| 796 | | |
| 797 | | // set the color, Z parameters to standard values |
| 798 | | for (int i = 0; i < 6; i++) |
| 799 | | { |
| 800 | | fsfx_vertices[i].z = 0.0f; |
| 801 | | fsfx_vertices[i].rhw = 1.0f; |
| 802 | | fsfx_vertices[i].color = D3DCOLOR_ARGB(255, 255, 255, 255); |
| 803 | | } |
| 804 | | } |
| 805 | | |
| 806 | | |
| 807 | | //============================================================ |
| 808 | | // shaders::create_resources |
| 809 | | //============================================================ |
| 810 | | |
| 811 | | int shaders::create_resources(bool reset) |
| 812 | | { |
| 813 | | if (!master_enable || !d3dintf->post_fx_available) |
| 814 | | { |
| 815 | | return 0; |
| 816 | | } |
| 817 | | |
| 818 | | HRESULT result = (*d3dintf->device.get_render_target)(d3d->get_device(), 0, &backbuffer); |
| 819 | | if (result != D3D_OK) |
| 820 | | { |
| 821 | | osd_printf_verbose("Direct3D: Error %08X during device get_render_target call\n", (int)result); |
| 822 | | } |
| 823 | | |
| 824 | | result = (*d3dintf->device.create_texture)(d3d->get_device(), 4, 4, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &black_texture); |
| 825 | | if (result != D3D_OK) |
| 826 | | { |
| 827 | | osd_printf_verbose("Direct3D: Unable to init video-memory target for black texture (%08x)\n", (UINT32)result); |
| 828 | | return 1; |
| 829 | | } |
| 830 | | (*d3dintf->texture.get_surface_level)(black_texture, 0, &black_surface); |
| 831 | | result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, black_surface); |
| 832 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); |
| 833 | | result = (*d3dintf->device.clear)(d3d->get_device(), 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); |
| 834 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result); |
| 835 | | result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, backbuffer); |
| 836 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); |
| 837 | | |
| 838 | | result = (*d3dintf->device.create_texture)(d3d->get_device(), (int)snap_width, (int)snap_height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &avi_copy_texture); |
| 839 | | if (result != D3D_OK) |
| 840 | | { |
| 841 | | osd_printf_verbose("Direct3D: Unable to init system-memory target for HLSL AVI dumping (%08x)\n", (UINT32)result); |
| 842 | | return 1; |
| 843 | | } |
| 844 | | (*d3dintf->texture.get_surface_level)(avi_copy_texture, 0, &avi_copy_surface); |
| 845 | | |
| 846 | | result = (*d3dintf->device.create_texture)(d3d->get_device(), (int)snap_width, (int)snap_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &avi_final_texture); |
| 847 | | if (result != D3D_OK) |
| 848 | | { |
| 849 | | osd_printf_verbose("Direct3D: Unable to init video-memory target for HLSL AVI dumping (%08x)\n", (UINT32)result); |
| 850 | | return 1; |
| 851 | | } |
| 852 | | (*d3dintf->texture.get_surface_level)(avi_final_texture, 0, &avi_final_target); |
| 853 | | |
| 854 | | emu_file file(machine->options().art_path(), OPEN_FLAG_READ); |
| 855 | | render_load_png(shadow_bitmap, file, NULL, options->shadow_mask_texture); |
| 856 | | |
| 857 | | // experimental: if we have a shadow bitmap, create a texture for it |
| 858 | | if (shadow_bitmap.valid()) |
| 859 | | { |
| 860 | | render_texinfo texture; |
| 861 | | |
| 862 | | // fake in the basic data so it looks like it came from render.c |
| 863 | | texture.base = shadow_bitmap.raw_pixptr(0); |
| 864 | | texture.rowpixels = shadow_bitmap.rowpixels(); |
| 865 | | texture.width = shadow_bitmap.width(); |
| 866 | | texture.height = shadow_bitmap.height(); |
| 867 | | texture.palette = NULL; |
| 868 | | texture.seqid = 0; |
| 869 | | |
| 870 | | // now create it (no prescale, but wrap) |
| 871 | | shadow_texture = new texture_info(d3d->get_texture_manager(), &texture, 1, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32) | PRIMFLAG_TEXWRAP_MASK); |
| 872 | | } |
| 873 | | |
| 874 | | const char *fx_dir = downcast<windows_options &>(machine->options()).screen_post_fx_dir(); |
| 875 | | |
| 876 | | default_effect = new effect(this, d3d->get_device(), "primary.fx", fx_dir); |
| 877 | | post_effect = new effect(this, d3d->get_device(), "post.fx", fx_dir); |
| 878 | | distortion_effect = new effect(this, d3d->get_device(), "distortion.fx", fx_dir); |
| 879 | | prescale_effect = new effect(this, d3d->get_device(), "prescale.fx", fx_dir); |
| 880 | | phosphor_effect = new effect(this, d3d->get_device(), "phosphor.fx", fx_dir); |
| 881 | | focus_effect = new effect(this, d3d->get_device(), "focus.fx", fx_dir); |
| 882 | | deconverge_effect = new effect(this, d3d->get_device(), "deconverge.fx", fx_dir); |
| 883 | | color_effect = new effect(this, d3d->get_device(), "color.fx", fx_dir); |
| 884 | | yiq_encode_effect = new effect(this, d3d->get_device(), "yiq_encode.fx", fx_dir); |
| 885 | | yiq_decode_effect = new effect(this, d3d->get_device(), "yiq_decode.fx", fx_dir); |
| 886 | | bloom_effect = new effect(this, d3d->get_device(), "bloom.fx", fx_dir); |
| 887 | | downsample_effect = new effect(this, d3d->get_device(), "downsample.fx", fx_dir); |
| 888 | | vector_effect = new effect(this, d3d->get_device(), "vector.fx", fx_dir); |
| 889 | | |
| 890 | | if (!default_effect->is_valid() || |
| 891 | | !post_effect->is_valid() || |
| 892 | | !distortion_effect->is_valid() || |
| 893 | | !prescale_effect->is_valid() || |
| 894 | | !phosphor_effect->is_valid() || |
| 895 | | !focus_effect->is_valid() || |
| 896 | | !deconverge_effect->is_valid() || |
| 897 | | !color_effect->is_valid() || |
| 898 | | !yiq_encode_effect->is_valid() || |
| 899 | | !yiq_decode_effect->is_valid() || |
| 900 | | !bloom_effect->is_valid() || |
| 901 | | !downsample_effect->is_valid() || |
| 902 | | !vector_effect->is_valid()) |
| 903 | | { |
| 904 | | return 1; |
| 905 | | } |
| 906 | | |
| 907 | | yiq_encode_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 908 | | yiq_encode_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS); |
| 909 | | yiq_encode_effect->add_uniform("SourceRect", uniform::UT_VEC2, uniform::CU_SOURCE_RECT); |
| 910 | | yiq_encode_effect->add_uniform("CCValue", uniform::UT_FLOAT, uniform::CU_NTSC_CCFREQ); |
| 911 | | yiq_encode_effect->add_uniform("AValue", uniform::UT_FLOAT, uniform::CU_NTSC_A); |
| 912 | | yiq_encode_effect->add_uniform("BValue", uniform::UT_FLOAT, uniform::CU_NTSC_B); |
| 913 | | yiq_encode_effect->add_uniform("PValue", uniform::UT_FLOAT, uniform::CU_NTSC_P); |
| 914 | | yiq_encode_effect->add_uniform("NotchHalfWidth", uniform::UT_FLOAT, uniform::CU_NTSC_NOTCH); |
| 915 | | yiq_encode_effect->add_uniform("YFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_YFREQ); |
| 916 | | yiq_encode_effect->add_uniform("IFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_IFREQ); |
| 917 | | yiq_encode_effect->add_uniform("QFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_QFREQ); |
| 918 | | yiq_encode_effect->add_uniform("ScanTime", uniform::UT_FLOAT, uniform::CU_NTSC_HTIME); |
| 919 | | |
| 920 | | yiq_decode_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 921 | | yiq_decode_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS); |
| 922 | | yiq_decode_effect->add_uniform("SourceRect", uniform::UT_VEC2, uniform::CU_SOURCE_RECT); |
| 923 | | yiq_decode_effect->add_uniform("CCValue", uniform::UT_FLOAT, uniform::CU_NTSC_CCFREQ); |
| 924 | | yiq_decode_effect->add_uniform("AValue", uniform::UT_FLOAT, uniform::CU_NTSC_A); |
| 925 | | yiq_decode_effect->add_uniform("BValue", uniform::UT_FLOAT, uniform::CU_NTSC_B); |
| 926 | | yiq_decode_effect->add_uniform("OValue", uniform::UT_FLOAT, uniform::CU_NTSC_O); |
| 927 | | yiq_decode_effect->add_uniform("PValue", uniform::UT_FLOAT, uniform::CU_NTSC_P); |
| 928 | | yiq_decode_effect->add_uniform("NotchHalfWidth", uniform::UT_FLOAT, uniform::CU_NTSC_NOTCH); |
| 929 | | yiq_decode_effect->add_uniform("YFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_YFREQ); |
| 930 | | yiq_decode_effect->add_uniform("IFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_IFREQ); |
| 931 | | yiq_decode_effect->add_uniform("QFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_QFREQ); |
| 932 | | yiq_decode_effect->add_uniform("ScanTime", uniform::UT_FLOAT, uniform::CU_NTSC_HTIME); |
| 933 | | |
| 934 | | color_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 935 | | color_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS); |
| 936 | | |
| 937 | | color_effect->add_uniform("YIQEnable", uniform::UT_FLOAT, uniform::CU_NTSC_ENABLE); |
| 938 | | color_effect->add_uniform("RedRatios", uniform::UT_VEC3, uniform::CU_COLOR_RED_RATIOS); |
| 939 | | color_effect->add_uniform("GrnRatios", uniform::UT_VEC3, uniform::CU_COLOR_GRN_RATIOS); |
| 940 | | color_effect->add_uniform("BluRatios", uniform::UT_VEC3, uniform::CU_COLOR_BLU_RATIOS); |
| 941 | | color_effect->add_uniform("Offset", uniform::UT_VEC3, uniform::CU_COLOR_OFFSET); |
| 942 | | color_effect->add_uniform("Scale", uniform::UT_VEC3, uniform::CU_COLOR_SCALE); |
| 943 | | color_effect->add_uniform("Saturation", uniform::UT_FLOAT, uniform::CU_COLOR_SATURATION); |
| 944 | | |
| 945 | | prescale_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 946 | | prescale_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS); |
| 947 | | |
| 948 | | deconverge_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 949 | | deconverge_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS); |
| 950 | | deconverge_effect->add_uniform("SourceRect", uniform::UT_VEC2, uniform::CU_SOURCE_RECT); |
| 951 | | deconverge_effect->add_uniform("ConvergeX", uniform::UT_VEC3, uniform::CU_CONVERGE_LINEAR_X); |
| 952 | | deconverge_effect->add_uniform("ConvergeY", uniform::UT_VEC3, uniform::CU_CONVERGE_LINEAR_Y); |
| 953 | | deconverge_effect->add_uniform("RadialConvergeX", uniform::UT_VEC3, uniform::CU_CONVERGE_RADIAL_X); |
| 954 | | deconverge_effect->add_uniform("RadialConvergeY", uniform::UT_VEC3, uniform::CU_CONVERGE_RADIAL_Y); |
| 955 | | |
| 956 | | focus_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 957 | | focus_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS); |
| 958 | | focus_effect->add_uniform("Defocus", uniform::UT_VEC2, uniform::CU_FOCUS_SIZE); |
| 959 | | |
| 960 | | phosphor_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 961 | | phosphor_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS); |
| 962 | | phosphor_effect->add_uniform("Phosphor", uniform::UT_VEC3, uniform::CU_PHOSPHOR_LIFE); |
| 963 | | |
| 964 | | downsample_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 965 | | |
| 966 | | bloom_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 967 | | bloom_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS); |
| 968 | | |
| 969 | | post_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS); |
| 970 | | post_effect->add_uniform("SourceRect", uniform::UT_VEC2, uniform::CU_SOURCE_RECT); // backward compatibility |
| 971 | | post_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 972 | | post_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS); |
| 973 | | post_effect->add_uniform("QuadDims", uniform::UT_VEC2, uniform::CU_QUAD_DIMS); // backward compatibility |
| 974 | | |
| 975 | | post_effect->add_uniform("VignettingAmount", uniform::UT_FLOAT, uniform::CU_POST_VIGNETTING); // backward compatibility |
| 976 | | post_effect->add_uniform("CurvatureAmount", uniform::UT_FLOAT, uniform::CU_POST_CURVATURE); // backward compatibility |
| 977 | | post_effect->add_uniform("RoundCornerAmount", uniform::UT_FLOAT, uniform::CU_POST_ROUND_CORNER); // backward compatibility |
| 978 | | post_effect->add_uniform("SmoothBorderAmount", uniform::UT_FLOAT, uniform::CU_POST_SMOOTH_BORDER); // backward compatibility |
| 979 | | post_effect->add_uniform("ReflectionAmount", uniform::UT_FLOAT, uniform::CU_POST_REFLECTION); // backward compatibility |
| 980 | | |
| 981 | | post_effect->add_uniform("ShadowAlpha", uniform::UT_FLOAT, uniform::CU_POST_SHADOW_ALPHA); |
| 982 | | post_effect->add_uniform("ShadowCount", uniform::UT_VEC2, uniform::CU_POST_SHADOW_COUNT); |
| 983 | | post_effect->add_uniform("ShadowUV", uniform::UT_VEC2, uniform::CU_POST_SHADOW_UV); |
| 984 | | post_effect->add_uniform("ShadowUVOffset", uniform::UT_VEC2, uniform::CU_POST_SHADOW_UV_OFFSET); |
| 985 | | post_effect->add_uniform("ShadowDims", uniform::UT_VEC2, uniform::CU_POST_SHADOW_DIMS); |
| 986 | | |
| 987 | | post_effect->add_uniform("ScanlineAlpha", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_ALPHA); |
| 988 | | post_effect->add_uniform("ScanlineScale", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_SCALE); |
| 989 | | post_effect->add_uniform("ScanlineHeight", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_HEIGHT); |
| 990 | | post_effect->add_uniform("ScanlineBrightScale", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_BRIGHT_SCALE); |
| 991 | | post_effect->add_uniform("ScanlineBrightOffset", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_BRIGHT_OFFSET); |
| 992 | | post_effect->add_uniform("Power", uniform::UT_VEC3, uniform::CU_POST_POWER); |
| 993 | | post_effect->add_uniform("Floor", uniform::UT_VEC3, uniform::CU_POST_FLOOR); |
| 994 | | |
| 995 | | distortion_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 996 | | distortion_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS); |
| 997 | | distortion_effect->add_uniform("QuadDims", uniform::UT_VEC2, uniform::CU_QUAD_DIMS); |
| 998 | | |
| 999 | | distortion_effect->add_uniform("VignettingAmount", uniform::UT_FLOAT, uniform::CU_POST_VIGNETTING); |
| 1000 | | distortion_effect->add_uniform("CurvatureAmount", uniform::UT_FLOAT, uniform::CU_POST_CURVATURE); |
| 1001 | | distortion_effect->add_uniform("RoundCornerAmount", uniform::UT_FLOAT, uniform::CU_POST_ROUND_CORNER); |
| 1002 | | distortion_effect->add_uniform("SmoothBorderAmount", uniform::UT_FLOAT, uniform::CU_POST_SMOOTH_BORDER); |
| 1003 | | distortion_effect->add_uniform("ReflectionAmount", uniform::UT_FLOAT, uniform::CU_POST_REFLECTION); |
| 1004 | | |
| 1005 | | vector_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 1006 | | |
| 1007 | | default_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 1008 | | default_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS); |
| 1009 | | |
| 1010 | | initialized = true; |
| 1011 | | |
| 1012 | | return 0; |
| 1013 | | } |
| 1014 | | |
| 1015 | | |
| 1016 | | //============================================================ |
| 1017 | | // shaders::begin_draw |
| 1018 | | //============================================================ |
| 1019 | | |
| 1020 | | void shaders::begin_draw() |
| 1021 | | { |
| 1022 | | if (!master_enable || !d3dintf->post_fx_available) |
| 1023 | | { |
| 1024 | | return; |
| 1025 | | } |
| 1026 | | |
| 1027 | | curr_effect = default_effect; |
| 1028 | | |
| 1029 | | default_effect->set_technique("TestTechnique"); |
| 1030 | | post_effect->set_technique("ScanMaskTechnique"); |
| 1031 | | distortion_effect->set_technique("DistortionTechnique"); |
| 1032 | | phosphor_effect->set_technique("TestTechnique"); |
| 1033 | | focus_effect->set_technique("TestTechnique"); |
| 1034 | | deconverge_effect->set_technique("DeconvergeTechnique"); |
| 1035 | | color_effect->set_technique("ColorTechnique"); |
| 1036 | | yiq_encode_effect->set_technique("EncodeTechnique"); |
| 1037 | | yiq_decode_effect->set_technique("DecodeTechnique"); |
| 1038 | | |
| 1039 | | HRESULT result = (*d3dintf->device.get_render_target)(d3d->get_device(), 0, &backbuffer); |
| 1040 | | if (result != D3D_OK) |
| 1041 | | { |
| 1042 | | osd_printf_verbose("Direct3D: Error %08X during device get_render_target call\n", (int)result); |
| 1043 | | } |
| 1044 | | } |
| 1045 | | |
| 1046 | | |
| 1047 | | //============================================================ |
| 1048 | | // shaders::begin_frame |
| 1049 | | //============================================================ |
| 1050 | | |
| 1051 | | void shaders::begin_frame() |
| 1052 | | { |
| 1053 | | record_texture(); |
| 1054 | | } |
| 1055 | | |
| 1056 | | |
| 1057 | | //============================================================ |
| 1058 | | // shaders::blit |
| 1059 | | //============================================================ |
| 1060 | | |
| 1061 | | void shaders::blit( |
| 1062 | | surface *dst, |
| 1063 | | bool clear_dst, |
| 1064 | | D3DPRIMITIVETYPE prim_type, |
| 1065 | | UINT32 prim_index, |
| 1066 | | UINT32 prim_count) |
| 1067 | | { |
| 1068 | | HRESULT result; |
| 1069 | | |
| 1070 | | if (dst != NULL) |
| 1071 | | { |
| 1072 | | result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, dst); |
| 1073 | | if (result != D3D_OK) |
| 1074 | | { |
| 1075 | | osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); |
| 1076 | | } |
| 1077 | | |
| 1078 | | if (clear_dst) |
| 1079 | | { |
| 1080 | | result = (*d3dintf->device.clear)(d3d->get_device(), 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(1,0,0,0), 0, 0); |
| 1081 | | if (result != D3D_OK) |
| 1082 | | { |
| 1083 | | osd_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result); |
| 1084 | | } |
| 1085 | | } |
| 1086 | | } |
| 1087 | | |
| 1088 | | UINT num_passes = 0; |
| 1089 | | curr_effect->begin(&num_passes, 0); |
| 1090 | | |
| 1091 | | for (UINT pass = 0; pass < num_passes; pass++) |
| 1092 | | { |
| 1093 | | curr_effect->begin_pass(pass); |
| 1094 | | |
| 1095 | | // add the primitives |
| 1096 | | result = (*d3dintf->device.draw_primitive)(d3d->get_device(), prim_type, prim_index, prim_count); |
| 1097 | | if (result != D3D_OK) |
| 1098 | | { |
| 1099 | | osd_printf_verbose("Direct3D: Error %08X during device draw_primitive call\n", (int)result); |
| 1100 | | } |
| 1101 | | |
| 1102 | | curr_effect->end_pass(); |
| 1103 | | } |
| 1104 | | |
| 1105 | | curr_effect->end(); |
| 1106 | | } |
| 1107 | | |
| 1108 | | |
| 1109 | | //============================================================ |
| 1110 | | // shaders::end_frame |
| 1111 | | //============================================================ |
| 1112 | | |
| 1113 | | void shaders::end_frame() |
| 1114 | | { |
| 1115 | | if (!master_enable || !d3dintf->post_fx_available) |
| 1116 | | { |
| 1117 | | return; |
| 1118 | | } |
| 1119 | | |
| 1120 | | if (render_snap && snap_rendered) |
| 1121 | | { |
| 1122 | | render_snapshot(snap_target); |
| 1123 | | } |
| 1124 | | |
| 1125 | | if (!lines_pending) |
| 1126 | | { |
| 1127 | | return; |
| 1128 | | } |
| 1129 | | |
| 1130 | | lines_pending = false; |
| 1131 | | } |
| 1132 | | |
| 1133 | | |
| 1134 | | //============================================================ |
| 1135 | | // shaders::init_effect_info |
| 1136 | | //============================================================ |
| 1137 | | |
| 1138 | | void shaders::init_effect_info(poly_info *poly) |
| 1139 | | { |
| 1140 | | // nothing to do |
| 1141 | | } |
| 1142 | | |
| 1143 | | |
| 1144 | | //============================================================ |
| 1145 | | // shaders::find_render_target |
| 1146 | | //============================================================ |
| 1147 | | |
| 1148 | | render_target* shaders::find_render_target(texture_info *info) |
| 1149 | | { |
| 1150 | | UINT32 screen_index_data = (UINT32)info->get_texinfo().osddata; |
| 1151 | | UINT32 screen_index = screen_index_data >> 1; |
| 1152 | | UINT32 page_index = screen_index_data & 1; |
| 1153 | | |
| 1154 | | render_target *curr = targethead; |
| 1155 | | while (curr != NULL && ( |
| 1156 | | curr->screen_index != screen_index || |
| 1157 | | curr->page_index != page_index || |
| 1158 | | curr->width != info->get_texinfo().width || |
| 1159 | | curr->height != info->get_texinfo().height)) |
| 1160 | | { |
| 1161 | | curr = curr->next; |
| 1162 | | } |
| 1163 | | |
| 1164 | | return curr; |
| 1165 | | } |
| 1166 | | |
| 1167 | | |
| 1168 | | //============================================================ |
| 1169 | | // shaders::find_render_target |
| 1170 | | //============================================================ |
| 1171 | | |
| 1172 | | render_target* shaders::find_render_target(int width, int height, UINT32 screen_index, UINT32 page_index) |
| 1173 | | { |
| 1174 | | render_target *curr = targethead; |
| 1175 | | while (curr != NULL && ( |
| 1176 | | curr->width != width || |
| 1177 | | curr->height != height || |
| 1178 | | curr->screen_index != screen_index || |
| 1179 | | curr->page_index != page_index)) |
| 1180 | | { |
| 1181 | | curr = curr->next; |
| 1182 | | } |
| 1183 | | |
| 1184 | | return curr; |
| 1185 | | } |
| 1186 | | |
| 1187 | | |
| 1188 | | //============================================================ |
| 1189 | | // shaders::find_cache_target |
| 1190 | | //============================================================ |
| 1191 | | |
| 1192 | | cache_target* shaders::find_cache_target(UINT32 screen_index, int width, int height) |
| 1193 | | { |
| 1194 | | cache_target *curr = cachehead; |
| 1195 | | while (curr != NULL && ( |
| 1196 | | curr->screen_index != screen_index || |
| 1197 | | curr->width != width || |
| 1198 | | curr->height != height)) |
| 1199 | | { |
| 1200 | | curr = curr->next; |
| 1201 | | } |
| 1202 | | |
| 1203 | | return curr; |
| 1204 | | } |
| 1205 | | |
| 1206 | | int shaders::ntsc_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1207 | | { |
| 1208 | | int next_index = source_index; |
| 1209 | | |
| 1210 | | if (!options->yiq_enable) |
| 1211 | | { |
| 1212 | | return next_index; |
| 1213 | | } |
| 1214 | | |
| 1215 | | // Convert our signal into YIQ |
| 1216 | | curr_effect = yiq_encode_effect; |
| 1217 | | curr_effect->update_uniforms(); |
| 1218 | | |
| 1219 | | // initial "Diffuse" texture is set in shaders::set_texture() |
| 1220 | | |
| 1221 | | next_index = rt->next_index(next_index); |
| 1222 | | blit(rt->native_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2); |
| 1223 | | |
| 1224 | | // Convert our signal from YIQ |
| 1225 | | curr_effect = yiq_decode_effect; |
| 1226 | | curr_effect->update_uniforms(); |
| 1227 | | curr_effect->set_texture("Composite", rt->native_texture[next_index]); |
| 1228 | | curr_effect->set_texture("Diffuse", curr_texture->get_finaltex()); |
| 1229 | | |
| 1230 | | next_index = rt->next_index(next_index); |
| 1231 | | blit(rt->native_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2); |
| 1232 | | |
| 1233 | | color_effect->set_texture("Diffuse", rt->native_texture[next_index]); |
| 1234 | | |
| 1235 | | return next_index; |
| 1236 | | } |
| 1237 | | |
| 1238 | | int shaders::color_convolution_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1239 | | { |
| 1240 | | int next_index = source_index; |
| 1241 | | |
| 1242 | | curr_effect = color_effect; |
| 1243 | | curr_effect->update_uniforms(); |
| 1244 | | |
| 1245 | | // initial "Diffuse" texture is set in shaders::set_texture() or the result of shaders::ntsc_pass() |
| 1246 | | |
| 1247 | | next_index = rt->next_index(next_index); |
| 1248 | | blit(rt->native_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2); |
| 1249 | | |
| 1250 | | return next_index; |
| 1251 | | } |
| 1252 | | |
| 1253 | | int shaders::prescale_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1254 | | { |
| 1255 | | int next_index = source_index; |
| 1256 | | |
| 1257 | | curr_effect = prescale_effect; |
| 1258 | | curr_effect->update_uniforms(); |
| 1259 | | curr_effect->set_texture("Diffuse", rt->native_texture[next_index]); |
| 1260 | | |
| 1261 | | next_index = rt->next_index(next_index); |
| 1262 | | blit(rt->prescale_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2); |
| 1263 | | |
| 1264 | | return next_index; |
| 1265 | | } |
| 1266 | | |
| 1267 | | int shaders::deconverge_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1268 | | { |
| 1269 | | int next_index = source_index; |
| 1270 | | |
| 1271 | | curr_effect = deconverge_effect; |
| 1272 | | curr_effect->update_uniforms(); |
| 1273 | | curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]); |
| 1274 | | |
| 1275 | | next_index = rt->next_index(next_index); |
| 1276 | | blit(rt->prescale_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2); |
| 1277 | | |
| 1278 | | return next_index; |
| 1279 | | } |
| 1280 | | |
| 1281 | | int shaders::defocus_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1282 | | { |
| 1283 | | int next_index = source_index; |
| 1284 | | |
| 1285 | | float defocus_x = options->defocus[0]; |
| 1286 | | float defocus_y = options->defocus[1]; |
| 1287 | | |
| 1288 | | // skip defocus if no influencing settings |
| 1289 | | if (defocus_x == 0.0f && defocus_y == 0.0f) |
| 1290 | | { |
| 1291 | | return next_index; |
| 1292 | | } |
| 1293 | | |
| 1294 | | curr_effect = focus_effect; |
| 1295 | | curr_effect->update_uniforms(); |
| 1296 | | curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]); |
| 1297 | | |
| 1298 | | next_index = rt->next_index(next_index); |
| 1299 | | blit(rt->prescale_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2); |
| 1300 | | |
| 1301 | | return next_index; |
| 1302 | | } |
| 1303 | | |
| 1304 | | int shaders::phosphor_pass(render_target *rt, cache_target *ct, int source_index, poly_info *poly, int vertnum) |
| 1305 | | { |
| 1306 | | int next_index = source_index; |
| 1307 | | |
| 1308 | | curr_effect = phosphor_effect; |
| 1309 | | curr_effect->update_uniforms(); |
| 1310 | | curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]); |
| 1311 | | curr_effect->set_texture("LastPass", ct->last_texture); |
| 1312 | | curr_effect->set_bool("Passthrough", false); |
| 1313 | | |
| 1314 | | next_index = rt->next_index(next_index); |
| 1315 | | blit(rt->prescale_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2); |
| 1316 | | |
| 1317 | | // Pass along our phosphor'd screen |
| 1318 | | curr_effect->update_uniforms(); |
| 1319 | | curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]); |
| 1320 | | curr_effect->set_texture("LastPass", rt->prescale_texture[next_index]); |
| 1321 | | curr_effect->set_bool("Passthrough", true); |
| 1322 | | |
| 1323 | | // Avoid changing targets due to page flipping |
| 1324 | | blit(ct->last_target, true, D3DPT_TRIANGLELIST, 0, 2); |
| 1325 | | |
| 1326 | | return next_index; |
| 1327 | | } |
| 1328 | | |
| 1329 | | int shaders::post_pass(render_target *rt, int source_index, poly_info *poly, int vertnum, bool prepare_bloom) |
| 1330 | | { |
| 1331 | | int next_index = source_index; |
| 1332 | | |
| 1333 | | texture_info *texture = poly->get_texture(); |
| 1334 | | |
| 1335 | | bool prepare_vector = |
| 1336 | | (machine->first_screen()->screen_type() & SCREEN_TYPE_VECTOR) == SCREEN_TYPE_VECTOR; |
| 1337 | | bool prepare_raster = |
| 1338 | | (machine->first_screen()->screen_type() & SCREEN_TYPE_RASTER) == SCREEN_TYPE_RASTER; |
| 1339 | | bool orientation_swap_xy = |
| 1340 | | (d3d->window().machine().system().flags & ORIENTATION_SWAP_XY) == ORIENTATION_SWAP_XY; |
| 1341 | | bool rotation_swap_xy = |
| 1342 | | (d3d->window().target()->orientation() & ROT90) == ROT90 || |
| 1343 | | (d3d->window().target()->orientation() & ROT270) == ROT270; |
| 1344 | | int rotation_type = |
| 1345 | | (d3d->window().target()->orientation() & ROT90) == ROT90 |
| 1346 | | ? 1 |
| 1347 | | : (d3d->window().target()->orientation() & ROT180) == ROT180 |
| 1348 | | ? 2 |
| 1349 | | : (d3d->window().target()->orientation() & ROT270) == ROT270 |
| 1350 | | ? 3 |
| 1351 | | : 0; |
| 1352 | | |
| 1353 | | curr_effect = post_effect; |
| 1354 | | curr_effect->update_uniforms(); |
| 1355 | | curr_effect->set_texture("ShadowTexture", shadow_texture == NULL ? NULL : shadow_texture->get_finaltex()); |
| 1356 | | curr_effect->set_texture("DiffuseTexture", rt->prescale_texture[next_index]); |
| 1357 | | curr_effect->set_float("ScanlineOffset", texture->get_cur_frame() == 0 ? 0.0f : options->scanline_offset); |
| 1358 | | curr_effect->set_bool("OrientationSwapXY", orientation_swap_xy); |
| 1359 | | curr_effect->set_bool("RotationSwapXY", rotation_swap_xy); |
| 1360 | | curr_effect->set_int("RotationType", rotation_type); // backward compatibility |
| 1361 | | curr_effect->set_bool("PrepareBloom", prepare_bloom); |
| 1362 | | curr_effect->set_bool("PrepareVector", prepare_vector); |
| 1363 | | curr_effect->set_bool("PrepareRaster", prepare_raster); |
| 1364 | | |
| 1365 | | next_index = rt->next_index(next_index); |
| 1366 | | blit(prepare_bloom ? rt->native_target[next_index] : rt->prescale_target[next_index], true, poly->get_type(), vertnum, poly->get_count()); |
| 1367 | | |
| 1368 | | return next_index; |
| 1369 | | } |
| 1370 | | |
| 1371 | | int shaders::downsample_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1372 | | { |
| 1373 | | int next_index = source_index; |
| 1374 | | |
| 1375 | | bool prepare_vector = |
| 1376 | | (machine->first_screen()->screen_type() & SCREEN_TYPE_VECTOR) == SCREEN_TYPE_VECTOR; |
| 1377 | | float bloom_rescale = options->bloom_scale; |
| 1378 | | |
| 1379 | | // skip downsample if no influencing settings |
| 1380 | | if (bloom_rescale == 0.0f) |
| 1381 | | { |
| 1382 | | return next_index; |
| 1383 | | } |
| 1384 | | |
| 1385 | | curr_effect = downsample_effect; |
| 1386 | | curr_effect->update_uniforms(); |
| 1387 | | curr_effect->set_bool("PrepareVector", prepare_vector); |
| 1388 | | |
| 1389 | | int bloom_index = 0; |
| 1390 | | float bloom_size = (d3d->get_width() < d3d->get_height()) ? d3d->get_width() : d3d->get_height(); |
| 1391 | | float bloom_width = prepare_vector ? rt->target_width : rt->target_width / hlsl_prescale_x; |
| 1392 | | float bloom_height = prepare_vector ? rt->target_height : rt->target_height / hlsl_prescale_y; |
| 1393 | | for (; bloom_size >= 2.0f && bloom_index < 11; bloom_size *= 0.5f) |
| 1394 | | { |
| 1395 | | bloom_dims[bloom_index][0] = (float)(int)bloom_width; |
| 1396 | | bloom_dims[bloom_index][1] = (float)(int)bloom_height; |
| 1397 | | |
| 1398 | | curr_effect->set_vector("TargetDims", 2, bloom_dims[bloom_index]); |
| 1399 | | curr_effect->set_texture("DiffuseTexture", |
| 1400 | | bloom_index == 0 |
| 1401 | | ? rt->native_texture[next_index] |
| 1402 | | : rt->bloom_texture[bloom_index - 1]); |
| 1403 | | |
| 1404 | | blit(rt->bloom_target[bloom_index], true, poly->get_type(), vertnum, poly->get_count()); |
| 1405 | | |
| 1406 | | bloom_width *= 0.5f; |
| 1407 | | bloom_height *= 0.5f; |
| 1408 | | |
| 1409 | | bloom_index++; |
| 1410 | | } |
| 1411 | | |
| 1412 | | bloom_count = bloom_index; |
| 1413 | | |
| 1414 | | return next_index; |
| 1415 | | } |
| 1416 | | |
| 1417 | | int shaders::bloom_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1418 | | { |
| 1419 | | int next_index = source_index; |
| 1420 | | |
| 1421 | | float bloom_rescale = options->bloom_scale; |
| 1422 | | |
| 1423 | | // skip bloom if no influencing settings |
| 1424 | | if (bloom_rescale == 0.0f) |
| 1425 | | { |
| 1426 | | return next_index; |
| 1427 | | } |
| 1428 | | |
| 1429 | | curr_effect = bloom_effect; |
| 1430 | | curr_effect->update_uniforms(); |
| 1431 | | |
| 1432 | | float weight0123[4] = { |
| 1433 | | options->bloom_level0_weight, |
| 1434 | | options->bloom_level1_weight * bloom_rescale, |
| 1435 | | options->bloom_level2_weight * bloom_rescale, |
| 1436 | | options->bloom_level3_weight * bloom_rescale |
| 1437 | | }; |
| 1438 | | float weight4567[4] = { |
| 1439 | | options->bloom_level4_weight * bloom_rescale, |
| 1440 | | options->bloom_level5_weight * bloom_rescale, |
| 1441 | | options->bloom_level6_weight * bloom_rescale, |
| 1442 | | options->bloom_level7_weight * bloom_rescale |
| 1443 | | }; |
| 1444 | | float weight89A[3] = { |
| 1445 | | options->bloom_level8_weight * bloom_rescale, |
| 1446 | | options->bloom_level9_weight * bloom_rescale, |
| 1447 | | options->bloom_level10_weight * bloom_rescale |
| 1448 | | }; |
| 1449 | | curr_effect->set_vector("Level0123Weight", 4, weight0123); |
| 1450 | | curr_effect->set_vector("Level4567Weight", 4, weight4567); |
| 1451 | | curr_effect->set_vector("Level89AWeight", 3, weight89A); |
| 1452 | | curr_effect->set_vector("Level01Size", 4, bloom_dims[0]); |
| 1453 | | curr_effect->set_vector("Level23Size", 4, bloom_dims[2]); |
| 1454 | | curr_effect->set_vector("Level45Size", 4, bloom_dims[4]); |
| 1455 | | curr_effect->set_vector("Level67Size", 4, bloom_dims[6]); |
| 1456 | | curr_effect->set_vector("Level89Size", 4, bloom_dims[8]); |
| 1457 | | curr_effect->set_vector("LevelASize", 2, bloom_dims[10]); |
| 1458 | | |
| 1459 | | curr_effect->set_vector("OverdriveWeight", 3, options->bloom_overdrive); |
| 1460 | | |
| 1461 | | curr_effect->set_texture("DiffuseA", rt->prescale_texture[next_index]); |
| 1462 | | |
| 1463 | | char name[9] = "Diffuse*"; |
| 1464 | | for (int index = 1; index < bloom_count; index++) |
| 1465 | | { |
| 1466 | | name[7] = 'A' + index; |
| 1467 | | curr_effect->set_texture(name, rt->bloom_texture[index - 1]); |
| 1468 | | } |
| 1469 | | for (int index = bloom_count; index < 11; index++) |
| 1470 | | { |
| 1471 | | name[7] = 'A' + index; |
| 1472 | | curr_effect->set_texture(name, black_texture); |
| 1473 | | } |
| 1474 | | |
| 1475 | | next_index = rt->next_index(next_index); |
| 1476 | | blit(rt->prescale_target[next_index], true, poly->get_type(), vertnum, poly->get_count()); |
| 1477 | | |
| 1478 | | return next_index; |
| 1479 | | } |
| 1480 | | |
| 1481 | | int shaders::distortion_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1482 | | { |
| 1483 | | int next_index = source_index; |
| 1484 | | |
| 1485 | | // skip distortion if no influencing settings |
| 1486 | | if (options->reflection == 0 && |
| 1487 | | options->vignetting == 0 && |
| 1488 | | options->curvature == 0 && |
| 1489 | | options->round_corner == 0 && |
| 1490 | | options->smooth_border == 0) |
| 1491 | | { |
| 1492 | | return next_index; |
| 1493 | | } |
| 1494 | | |
| 1495 | | int screen_count = d3d->window().target()->current_view()->screens().count(); |
| 1496 | | |
| 1497 | | // only one screen is supported |
| 1498 | | if (screen_count > 1) |
| 1499 | | { |
| 1500 | | return next_index; |
| 1501 | | } |
| 1502 | | |
| 1503 | | render_bounds bounds = d3d->window().target()->current_view()->bounds(); |
| 1504 | | render_bounds screen_bounds = d3d->window().target()->current_view()->screen_bounds(); |
| 1505 | | |
| 1506 | | // artworks are not supported |
| 1507 | | if (bounds.x0 != screen_bounds.x0 || |
| 1508 | | bounds.y0 != screen_bounds.y0 || |
| 1509 | | bounds.x1 != screen_bounds.x1 || |
| 1510 | | bounds.y1 != screen_bounds.y1) |
| 1511 | | { |
| 1512 | | return next_index; |
| 1513 | | } |
| 1514 | | |
| 1515 | | bool orientation_swap_xy = |
| 1516 | | (d3d->window().machine().system().flags & ORIENTATION_SWAP_XY) == ORIENTATION_SWAP_XY; |
| 1517 | | bool rotation_swap_xy = |
| 1518 | | (d3d->window().target()->orientation() & ROT90) == ROT90 || |
| 1519 | | (d3d->window().target()->orientation() & ROT270) == ROT270; |
| 1520 | | int rotation_type = |
| 1521 | | (d3d->window().target()->orientation() & ROT90) == ROT90 |
| 1522 | | ? 1 |
| 1523 | | : (d3d->window().target()->orientation() & ROT180) == ROT180 |
| 1524 | | ? 2 |
| 1525 | | : (d3d->window().target()->orientation() & ROT270) == ROT270 |
| 1526 | | ? 3 |
| 1527 | | : 0; |
| 1528 | | |
| 1529 | | curr_effect = distortion_effect; |
| 1530 | | curr_effect->update_uniforms(); |
| 1531 | | curr_effect->set_texture("DiffuseTexture", rt->prescale_texture[next_index]); |
| 1532 | | curr_effect->set_bool("OrientationSwapXY", orientation_swap_xy); |
| 1533 | | curr_effect->set_bool("RotationSwapXY", rotation_swap_xy); |
| 1534 | | curr_effect->set_int("RotationType", rotation_type); |
| 1535 | | |
| 1536 | | next_index = rt->next_index(next_index); |
| 1537 | | blit(rt->prescale_target[next_index], true, poly->get_type(), vertnum, poly->get_count()); |
| 1538 | | |
| 1539 | | return next_index; |
| 1540 | | } |
| 1541 | | |
| 1542 | | int shaders::vector_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1543 | | { |
| 1544 | | int next_index = source_index; |
| 1545 | | |
| 1546 | | float time_params[2] = { 0.0f, 0.0f }; |
| 1547 | | float length_params[3] = { poly->get_line_length(), options->vector_length_scale, options->vector_length_ratio }; |
| 1548 | | |
| 1549 | | curr_effect = vector_effect; |
| 1550 | | curr_effect->update_uniforms(); |
| 1551 | | curr_effect->set_vector("TimeParams", 2, time_params); |
| 1552 | | curr_effect->set_vector("LengthParams", 3, length_params); |
| 1553 | | |
| 1554 | | blit(rt->prescale_target[next_index], true, poly->get_type(), vertnum, poly->get_count()); |
| 1555 | | |
| 1556 | | return next_index; |
| 1557 | | } |
| 1558 | | |
| 1559 | | int shaders::vector_buffer_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1560 | | { |
| 1561 | | int next_index = source_index; |
| 1562 | | |
| 1563 | | curr_effect = default_effect; |
| 1564 | | curr_effect->update_uniforms(); |
| 1565 | | |
| 1566 | | curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]); |
| 1567 | | curr_effect->set_bool("PostPass", true); |
| 1568 | | curr_effect->set_float("Brighten", 1.0f); |
| 1569 | | |
| 1570 | | next_index = rt->next_index(next_index); |
| 1571 | | blit(rt->prescale_target[next_index], true, poly->get_type(), vertnum, poly->get_count()); |
| 1572 | | |
| 1573 | | return next_index; |
| 1574 | | } |
| 1575 | | |
| 1576 | | int shaders::screen_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1577 | | { |
| 1578 | | int next_index = source_index; |
| 1579 | | |
| 1580 | | bool prepare_vector = |
| 1581 | | (machine->first_screen()->screen_type() & SCREEN_TYPE_VECTOR) == SCREEN_TYPE_VECTOR; |
| 1582 | | |
| 1583 | | curr_effect = default_effect; |
| 1584 | | curr_effect->update_uniforms(); |
| 1585 | | |
| 1586 | | curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]); |
| 1587 | | curr_effect->set_bool("PostPass", true); |
| 1588 | | curr_effect->set_float("Brighten", prepare_vector ? 1.0f : 0.0f); |
| 1589 | | |
| 1590 | | // we do not clear the backbuffe here because multiple screens might rendered into |
| 1591 | | blit(backbuffer, false, poly->get_type(), vertnum, poly->get_count()); |
| 1592 | | |
| 1593 | | if (avi_output_file != NULL) |
| 1594 | | { |
| 1595 | | blit(avi_final_target, false, poly->get_type(), vertnum, poly->get_count()); |
| 1596 | | } |
| 1597 | | |
| 1598 | | if (render_snap) |
| 1599 | | { |
| 1600 | | blit(snap_target, false, poly->get_type(), vertnum, poly->get_count()); |
| 1601 | | |
| 1602 | | snap_rendered = true; |
| 1603 | | } |
| 1604 | | |
| 1605 | | return next_index; |
| 1606 | | } |
| 1607 | | |
| 1608 | | void shaders::menu_pass(poly_info *poly, int vertnum) |
| 1609 | | { |
| 1610 | | curr_effect = default_effect; |
| 1611 | | curr_effect->update_uniforms(); |
| 1612 | | curr_effect->set_bool("PostPass", false); |
| 1613 | | curr_effect->set_float("Brighten", 0.0f); |
| 1614 | | |
| 1615 | | blit(NULL, false, poly->get_type(), vertnum, poly->get_count()); |
| 1616 | | } |
| 1617 | | |
| 1618 | | |
| 1619 | | //============================================================ |
| 1620 | | // shaders::render_quad |
| 1621 | | //============================================================ |
| 1622 | | |
| 1623 | | void shaders::render_quad(poly_info *poly, int vertnum) |
| 1624 | | { |
| 1625 | | if (!master_enable || !d3dintf->post_fx_available) |
| 1626 | | { |
| 1627 | | return; |
| 1628 | | } |
| 1629 | | |
| 1630 | | curr_texture = poly->get_texture(); |
| 1631 | | curr_poly = poly; |
| 1632 | | |
| 1633 | | if (PRIMFLAG_GET_SCREENTEX(d3d->get_last_texture_flags()) && curr_texture != NULL) |
| 1634 | | { |
| 1635 | | curr_render_target = find_render_target(curr_texture); |
| 1636 | | |
| 1637 | | render_target *rt = curr_render_target; |
| 1638 | | if (rt == NULL) |
| 1639 | | { |
| 1640 | | return; |
| 1641 | | } |
| 1642 | | |
| 1643 | | cache_target *ct = find_cache_target(rt->screen_index, curr_texture->get_texinfo().width, curr_texture->get_texinfo().height); |
| 1644 | | |
| 1645 | | int next_index = 0; |
| 1646 | | |
| 1647 | | next_index = ntsc_pass(rt, next_index, poly, vertnum); |
| 1648 | | next_index = color_convolution_pass(rt, next_index, poly, vertnum); |
| 1649 | | next_index = prescale_pass(rt, next_index, poly, vertnum); |
| 1650 | | next_index = deconverge_pass(rt, next_index, poly, vertnum); |
| 1651 | | next_index = defocus_pass(rt, next_index, poly, vertnum); // 1st pass |
| 1652 | | next_index = defocus_pass(rt, next_index, poly, vertnum); // 2nd pass |
| 1653 | | next_index = phosphor_pass(rt, ct, next_index, poly, vertnum); |
| 1654 | | |
| 1655 | | // create bloom textures |
| 1656 | | int phosphor_index = next_index; |
| 1657 | | next_index = post_pass(rt, next_index, poly, vertnum, true); |
| 1658 | | next_index = downsample_pass(rt, next_index, poly, vertnum); |
| 1659 | | |
| 1660 | | // apply bloom textures |
| 1661 | | next_index = phosphor_index; |
| 1662 | | next_index = post_pass(rt, next_index, poly, vertnum, false); |
| 1663 | | next_index = bloom_pass(rt, next_index, poly, vertnum); |
| 1664 | | |
| 1665 | | next_index = distortion_pass(rt, next_index, poly, vertnum); |
| 1666 | | |
| 1667 | | // render on screen |
| 1668 | | d3d->set_wrap(D3DTADDRESS_MIRROR); |
| 1669 | | next_index = screen_pass(rt, next_index, poly, vertnum); |
| 1670 | | d3d->set_wrap(PRIMFLAG_GET_TEXWRAP(poly->get_texture()->get_flags()) ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP); |
| 1671 | | |
| 1672 | | curr_texture->increment_frame_count(); |
| 1673 | | curr_texture->mask_frame_count(options->yiq_phase_count); |
| 1674 | | |
| 1675 | | options->params_dirty = false; |
| 1676 | | } |
| 1677 | | else if (PRIMFLAG_GET_VECTOR(poly->get_flags()) && vector_enable) |
| 1678 | | { |
| 1679 | | curr_render_target = find_render_target(d3d->get_width(), d3d->get_height(), 0, 0); |
| 1680 | | |
| 1681 | | render_target *rt = curr_render_target; |
| 1682 | | if (rt == NULL) |
| 1683 | | { |
| 1684 | | return; |
| 1685 | | } |
| 1686 | | |
| 1687 | | lines_pending = true; |
| 1688 | | |
| 1689 | | int next_index = 0; |
| 1690 | | |
| 1691 | | next_index = vector_pass(rt, next_index, poly, vertnum); |
| 1692 | | |
| 1693 | | HRESULT result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, backbuffer); |
| 1694 | | if (result != D3D_OK) |
| 1695 | | { |
| 1696 | | osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); |
| 1697 | | } |
| 1698 | | } |
| 1699 | | else if (PRIMFLAG_GET_VECTORBUF(poly->get_flags()) && vector_enable) |
| 1700 | | { |
| 1701 | | curr_render_target = find_render_target(d3d->get_width(), d3d->get_height(), 0, 0); |
| 1702 | | |
| 1703 | | render_target *rt = curr_render_target; |
| 1704 | | if (rt == NULL) |
| 1705 | | { |
| 1706 | | return; |
| 1707 | | } |
| 1708 | | |
| 1709 | | cache_target *ct = find_cache_target(rt->screen_index, rt->width, rt->height); |
| 1710 | | |
| 1711 | | int next_index = 0; |
| 1712 | | |
| 1713 | | next_index = vector_buffer_pass(rt, next_index, poly, vertnum); |
| 1714 | | next_index = defocus_pass(rt, next_index, poly, vertnum); |
| 1715 | | next_index = phosphor_pass(rt, ct, next_index, poly, vertnum); |
| 1716 | | |
| 1717 | | // create bloom textures |
| 1718 | | int phosphor_index = next_index; |
| 1719 | | next_index = post_pass(rt, next_index, poly, vertnum, true); |
| 1720 | | next_index = downsample_pass(rt, next_index, poly, vertnum); |
| 1721 | | |
| 1722 | | // apply bloom textures |
| 1723 | | next_index = phosphor_index; |
| 1724 | | next_index = post_pass(rt, next_index, poly, vertnum, false); |
| 1725 | | next_index = bloom_pass(rt, next_index, poly, vertnum); |
| 1726 | | |
| 1727 | | next_index = distortion_pass(rt, next_index, poly, vertnum); |
| 1728 | | |
| 1729 | | // render on screen |
| 1730 | | next_index = screen_pass(rt, next_index, poly, vertnum); |
| 1731 | | |
| 1732 | | HRESULT result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, backbuffer); |
| 1733 | | if (result != D3D_OK) |
| 1734 | | { |
| 1735 | | osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); |
| 1736 | | } |
| 1737 | | |
| 1738 | | lines_pending = false; |
| 1739 | | } |
| 1740 | | else |
| 1741 | | { |
| 1742 | | menu_pass(poly, vertnum); |
| 1743 | | } |
| 1744 | | |
| 1745 | | curr_render_target = NULL; |
| 1746 | | curr_texture = NULL; |
| 1747 | | curr_poly = NULL; |
| 1748 | | } |
| 1749 | | |
| 1750 | | |
| 1751 | | //============================================================ |
| 1752 | | // shaders::end_draw |
| 1753 | | //============================================================ |
| 1754 | | |
| 1755 | | void shaders::end_draw() |
| 1756 | | { |
| 1757 | | if (!master_enable || !d3dintf->post_fx_available) |
| 1758 | | { |
| 1759 | | return; |
| 1760 | | } |
| 1761 | | |
| 1762 | | (*d3dintf->surface.release)(backbuffer); |
| 1763 | | } |
| 1764 | | |
| 1765 | | |
| 1766 | | //============================================================ |
| 1767 | | // shaders::register_prescaled_texture |
| 1768 | | //============================================================ |
| 1769 | | |
| 1770 | | bool shaders::register_prescaled_texture(texture_info *texture) |
| 1771 | | { |
| 1772 | | return register_texture(texture); |
| 1773 | | } |
| 1774 | | |
| 1775 | | |
| 1776 | | //============================================================ |
| 1777 | | // shaders::add_cache_target - register a cache target |
| 1778 | | //============================================================ |
| 1779 | | bool shaders::add_cache_target(renderer* d3d, texture_info* info, int width, int height, int xprescale, int yprescale, int screen_index) |
| 1780 | | { |
| 1781 | | cache_target* target = (cache_target*)global_alloc_clear(cache_target); |
| 1782 | | |
| 1783 | | if (!target->init(d3d, d3dintf, width, height, xprescale, yprescale)) |
| 1784 | | { |
| 1785 | | global_free(target); |
| 1786 | | return false; |
| 1787 | | } |
| 1788 | | |
| 1789 | | if (info != NULL) |
| 1790 | | { |
| 1791 | | target->width = info->get_texinfo().width; |
| 1792 | | target->height = info->get_texinfo().height; |
| 1793 | | } |
| 1794 | | else |
| 1795 | | { |
| 1796 | | target->width = d3d->get_width(); |
| 1797 | | target->height = d3d->get_height(); |
| 1798 | | } |
| 1799 | | |
| 1800 | | target->next = cachehead; |
| 1801 | | target->prev = NULL; |
| 1802 | | |
| 1803 | | target->screen_index = screen_index; |
| 1804 | | |
| 1805 | | if (cachehead != NULL) |
| 1806 | | { |
| 1807 | | cachehead->prev = target; |
| 1808 | | } |
| 1809 | | cachehead = target; |
| 1810 | | |
| 1811 | | return true; |
| 1812 | | } |
| 1813 | | |
| 1814 | | render_target* shaders::get_vector_target() |
| 1815 | | { |
| 1816 | | if (!vector_enable) |
| 1817 | | { |
| 1818 | | return NULL; |
| 1819 | | } |
| 1820 | | |
| 1821 | | return find_render_target(d3d->get_width(), d3d->get_height(), 0, 0); |
| 1822 | | } |
| 1823 | | |
| 1824 | | void shaders::create_vector_target(render_primitive *prim) |
| 1825 | | { |
| 1826 | | if (!add_render_target(d3d, NULL, d3d->get_width(), d3d->get_height(), 1, 1)) |
| 1827 | | { |
| 1828 | | vector_enable = false; |
| 1829 | | } |
| 1830 | | } |
| 1831 | | |
| 1832 | | |
| 1833 | | //============================================================ |
| 1834 | | // shaders::add_render_target - register a render target |
| 1835 | | //============================================================ |
| 1836 | | |
| 1837 | | bool shaders::add_render_target(renderer* d3d, texture_info* info, int width, int height, int xprescale, int yprescale) |
| 1838 | | { |
| 1839 | | UINT32 screen_index = 0; |
| 1840 | | UINT32 page_index = 0; |
| 1841 | | if (info != NULL) |
| 1842 | | { |
| 1843 | | render_target *existing_target = find_render_target(info); |
| 1844 | | if (existing_target != NULL) |
| 1845 | | { |
| 1846 | | remove_render_target(existing_target); |
| 1847 | | } |
| 1848 | | |
| 1849 | | UINT32 screen_index_data = (UINT32)info->get_texinfo().osddata; |
| 1850 | | screen_index = screen_index_data >> 1; |
| 1851 | | page_index = screen_index_data & 1; |
| 1852 | | } |
| 1853 | | else |
| 1854 | | { |
| 1855 | | render_target *existing_target = find_render_target(d3d->get_width(), d3d->get_height(), 0, 0); |
| 1856 | | if (existing_target != NULL) |
| 1857 | | { |
| 1858 | | remove_render_target(existing_target); |
| 1859 | | } |
| 1860 | | } |
| 1861 | | |
| 1862 | | render_target* target = (render_target*)global_alloc_clear(render_target); |
| 1863 | | |
| 1864 | | if (!target->init(d3d, d3dintf, width, height, xprescale, yprescale)) |
| 1865 | | { |
| 1866 | | global_free(target); |
| 1867 | | return false; |
| 1868 | | } |
| 1869 | | |
| 1870 | | if (info != NULL) |
| 1871 | | { |
| 1872 | | target->width = info->get_texinfo().width; |
| 1873 | | target->height = info->get_texinfo().height; |
| 1874 | | } |
| 1875 | | else |
| 1876 | | { |
| 1877 | | target->width = d3d->get_width(); |
| 1878 | | target->height = d3d->get_height(); |
| 1879 | | } |
| 1880 | | |
| 1881 | | HRESULT result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, target->prescale_target[0]); |
| 1882 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); |
| 1883 | | result = (*d3dintf->device.clear)(d3d->get_device(), 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); |
| 1884 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result); |
| 1885 | | result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, backbuffer); |
| 1886 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); |
| 1887 | | |
| 1888 | | target->screen_index = screen_index; |
| 1889 | | target->page_index = page_index; |
| 1890 | | |
| 1891 | | cache_target* cache = find_cache_target(target->screen_index, target->width, target->height); |
| 1892 | | if (cache == NULL) |
| 1893 | | { |
| 1894 | | if (!add_cache_target(d3d, info, width, height, xprescale, yprescale, target->screen_index)) |
| 1895 | | { |
| 1896 | | global_free(target); |
| 1897 | | return false; |
| 1898 | | } |
| 1899 | | } |
| 1900 | | |
| 1901 | | target->next = targethead; |
| 1902 | | target->prev = NULL; |
| 1903 | | |
| 1904 | | if (targethead != NULL) |
| 1905 | | { |
| 1906 | | targethead->prev = target; |
| 1907 | | } |
| 1908 | | targethead = target; |
| 1909 | | |
| 1910 | | return true; |
| 1911 | | } |
| 1912 | | |
| 1913 | | |
| 1914 | | //============================================================ |
| 1915 | | // shaders::enumerate_screens |
| 1916 | | //============================================================ |
| 1917 | | void shaders::enumerate_screens() |
| 1918 | | { |
| 1919 | | screen_device_iterator iter(machine->root_device()); |
| 1920 | | num_screens = iter.count(); |
| 1921 | | } |
| 1922 | | |
| 1923 | | |
| 1924 | | //============================================================ |
| 1925 | | // shaders::register_texture(texture::info) |
| 1926 | | //============================================================ |
| 1927 | | |
| 1928 | | bool shaders::register_texture(texture_info *texture) |
| 1929 | | { |
| 1930 | | int width = texture->get_width(); |
| 1931 | | int height = texture->get_height(); |
| 1932 | | int xscale = texture->get_xscale(); |
| 1933 | | int yscale = texture->get_yscale(); |
| 1934 | | |
| 1935 | | if (!master_enable || !d3dintf->post_fx_available) |
| 1936 | | { |
| 1937 | | return false; |
| 1938 | | } |
| 1939 | | |
| 1940 | | enumerate_screens(); |
| 1941 | | |
| 1942 | | // Find the nearest prescale factor that is over our screen size |
| 1943 | | if (hlsl_prescale_x == 0) |
| 1944 | | { |
| 1945 | | hlsl_prescale_x = 1; |
| 1946 | | while (width * xscale * hlsl_prescale_x <= d3d->get_width()) |
| 1947 | | { |
| 1948 | | hlsl_prescale_x++; |
| 1949 | | } |
| 1950 | | hlsl_prescale_x--; |
| 1951 | | } |
| 1952 | | |
| 1953 | | if (hlsl_prescale_y == 0) |
| 1954 | | { |
| 1955 | | hlsl_prescale_y = 1; |
| 1956 | | while (height * yscale * hlsl_prescale_y <= d3d->get_height()) |
| 1957 | | { |
| 1958 | | hlsl_prescale_y++; |
| 1959 | | } |
| 1960 | | hlsl_prescale_y--; |
| 1961 | | } |
| 1962 | | |
| 1963 | | hlsl_prescale_x = ((hlsl_prescale_x == 0) ? 1 : hlsl_prescale_x); |
| 1964 | | hlsl_prescale_y = ((hlsl_prescale_y == 0) ? 1 : hlsl_prescale_y); |
| 1965 | | |
| 1966 | | if (!add_render_target(d3d, texture, width, height, xscale * hlsl_prescale_x, yscale * hlsl_prescale_y)) |
| 1967 | | { |
| 1968 | | return false; |
| 1969 | | } |
| 1970 | | |
| 1971 | | options->params_dirty = true; |
| 1972 | | |
| 1973 | | return true; |
| 1974 | | } |
| 1975 | | |
| 1976 | | |
| 1977 | | //============================================================ |
| 1978 | | // shaders::delete_resources |
| 1979 | | //============================================================ |
| 1980 | | |
| 1981 | | void shaders::delete_resources(bool reset) |
| 1982 | | { |
| 1983 | | if (!master_enable || !d3dintf->post_fx_available) |
| 1984 | | { |
| 1985 | | return; |
| 1986 | | } |
| 1987 | | |
| 1988 | | initialized = false; |
| 1989 | | |
| 1990 | | options = NULL; |
| 1991 | | |
| 1992 | | cache_target *currcache = cachehead; |
| 1993 | | while(cachehead != NULL) |
| 1994 | | { |
| 1995 | | cachehead = currcache->next; |
| 1996 | | global_free(currcache); |
| 1997 | | currcache = cachehead; |
| 1998 | | } |
| 1999 | | |
| 2000 | | render_target *currtarget = targethead; |
| 2001 | | while(targethead != NULL) |
| 2002 | | { |
| 2003 | | targethead = currtarget->next; |
| 2004 | | global_free(currtarget); |
| 2005 | | currtarget = targethead; |
| 2006 | | } |
| 2007 | | |
| 2008 | | if (downsample_effect != NULL) |
| 2009 | | { |
| 2010 | | delete downsample_effect; |
| 2011 | | downsample_effect = NULL; |
| 2012 | | } |
| 2013 | | if (bloom_effect != NULL) |
| 2014 | | { |
| 2015 | | delete bloom_effect; |
| 2016 | | bloom_effect = NULL; |
| 2017 | | } |
| 2018 | | if (vector_effect != NULL) |
| 2019 | | { |
| 2020 | | delete vector_effect; |
| 2021 | | vector_effect = NULL; |
| 2022 | | } |
| 2023 | | if (default_effect != NULL) |
| 2024 | | { |
| 2025 | | delete default_effect; |
| 2026 | | default_effect = NULL; |
| 2027 | | } |
| 2028 | | if (post_effect != NULL) |
| 2029 | | { |
| 2030 | | delete post_effect; |
| 2031 | | post_effect = NULL; |
| 2032 | | } |
| 2033 | | if (distortion_effect != NULL) |
| 2034 | | { |
| 2035 | | delete distortion_effect; |
| 2036 | | distortion_effect = NULL; |
| 2037 | | } |
| 2038 | | if (prescale_effect != NULL) |
| 2039 | | { |
| 2040 | | delete prescale_effect; |
| 2041 | | prescale_effect = NULL; |
| 2042 | | } |
| 2043 | | if (phosphor_effect != NULL) |
| 2044 | | { |
| 2045 | | delete phosphor_effect; |
| 2046 | | phosphor_effect = NULL; |
| 2047 | | } |
| 2048 | | if (focus_effect != NULL) |
| 2049 | | { |
| 2050 | | delete focus_effect; |
| 2051 | | focus_effect = NULL; |
| 2052 | | } |
| 2053 | | if (deconverge_effect != NULL) |
| 2054 | | { |
| 2055 | | delete deconverge_effect; |
| 2056 | | deconverge_effect = NULL; |
| 2057 | | } |
| 2058 | | if (color_effect != NULL) |
| 2059 | | { |
| 2060 | | delete color_effect; |
| 2061 | | color_effect = NULL; |
| 2062 | | } |
| 2063 | | if (yiq_encode_effect != NULL) |
| 2064 | | { |
| 2065 | | delete yiq_encode_effect; |
| 2066 | | yiq_encode_effect = NULL; |
| 2067 | | } |
| 2068 | | if (yiq_decode_effect != NULL) |
| 2069 | | { |
| 2070 | | delete yiq_decode_effect; |
| 2071 | | yiq_decode_effect = NULL; |
| 2072 | | } |
| 2073 | | |
| 2074 | | if (backbuffer != NULL) |
| 2075 | | { |
| 2076 | | (*d3dintf->surface.release)(backbuffer); |
| 2077 | | backbuffer = NULL; |
| 2078 | | } |
| 2079 | | |
| 2080 | | if (black_surface != NULL) |
| 2081 | | { |
| 2082 | | (*d3dintf->surface.release)(black_surface); |
| 2083 | | black_surface = NULL; |
| 2084 | | } |
| 2085 | | if (black_texture != NULL) |
| 2086 | | { |
| 2087 | | (*d3dintf->texture.release)(black_texture); |
| 2088 | | black_texture = NULL; |
| 2089 | | } |
| 2090 | | |
| 2091 | | if (avi_copy_texture != NULL) |
| 2092 | | { |
| 2093 | | (*d3dintf->texture.release)(avi_copy_texture); |
| 2094 | | avi_copy_texture = NULL; |
| 2095 | | } |
| 2096 | | |
| 2097 | | if (avi_copy_surface != NULL) |
| 2098 | | { |
| 2099 | | (*d3dintf->surface.release)(avi_copy_surface); |
| 2100 | | avi_copy_surface = NULL; |
| 2101 | | } |
| 2102 | | |
| 2103 | | if (avi_final_texture != NULL) |
| 2104 | | { |
| 2105 | | (*d3dintf->texture.release)(avi_final_texture); |
| 2106 | | avi_final_texture = NULL; |
| 2107 | | } |
| 2108 | | |
| 2109 | | if (avi_final_target != NULL) |
| 2110 | | { |
| 2111 | | (*d3dintf->surface.release)(avi_final_target); |
| 2112 | | avi_final_target = NULL; |
| 2113 | | } |
| 2114 | | |
| 2115 | | shadow_bitmap.reset(); |
| 2116 | | } |
| 2117 | | |
| 2118 | | |
| 2119 | | //============================================================ |
| 2120 | | // get_vector |
| 2121 | | //============================================================ |
| 2122 | | |
| 2123 | | static void get_vector(const char *data, int count, float *out, bool report_error) |
| 2124 | | { |
| 2125 | | if (count > 3 && |
| 2126 | | sscanf(data, "%f,%f,%f,%f", &out[0], &out[1], &out[2], &out[3]) < 4 && report_error) |
| 2127 | | { |
| 2128 | | osd_printf_error("Illegal quad vector value = %s\n", data); |
| 2129 | | } |
| 2130 | | else if (count > 2 && |
| 2131 | | sscanf(data, "%f,%f,%f", &out[0], &out[1], &out[2]) < 3 && report_error) |
| 2132 | | { |
| 2133 | | osd_printf_error("Illegal triple vector value = %s\n", data); |
| 2134 | | } |
| 2135 | | else if (count > 1 && |
| 2136 | | sscanf(data, "%f,%f", &out[0], &out[1]) < 2 && report_error) |
| 2137 | | { |
| 2138 | | osd_printf_error("Illegal double vector value = %s\n", data); |
| 2139 | | } |
| 2140 | | else if (count > 0 && |
| 2141 | | sscanf(data, "%f", &out[0]) < 1 && report_error) |
| 2142 | | { |
| 2143 | | osd_printf_error("Illegal single vector value = %s\n", data); |
| 2144 | | } |
| 2145 | | } |
| 2146 | | |
| 2147 | | |
| 2148 | | /*------------------------------------------------- |
| 2149 | | slider_alloc - allocate a new slider entry |
| 2150 | | currently duplicated from ui.c, this could |
| 2151 | | be done in a more ideal way. |
| 2152 | | -------------------------------------------------*/ |
| 2153 | | |
| 2154 | | static slider_state *slider_alloc(running_machine &machine, const char *title, INT32 minval, INT32 defval, INT32 maxval, INT32 incval, slider_update update, void *arg) |
| 2155 | | { |
| 2156 | | int size = sizeof(slider_state) + strlen(title); |
| 2157 | | slider_state *state = (slider_state *)auto_alloc_array_clear(machine, UINT8, size); |
| 2158 | | |
| 2159 | | state->minval = minval; |
| 2160 | | state->defval = defval; |
| 2161 | | state->maxval = maxval; |
| 2162 | | state->incval = incval; |
| 2163 | | state->update = update; |
| 2164 | | state->arg = arg; |
| 2165 | | strcpy(state->description, title); |
| 2166 | | |
| 2167 | | return state; |
| 2168 | | } |
| 2169 | | |
| 2170 | | |
| 2171 | | //============================================================ |
| 2172 | | // assorted global slider accessors |
| 2173 | | //============================================================ |
| 2174 | | |
| 2175 | | static INT32 slider_set(float *option, float scale, const char *fmt, std::string *str, INT32 newval) |
| 2176 | | { |
| 2177 | | if (option != NULL && newval != SLIDER_NOCHANGE) |
| 2178 | | { |
| 2179 | | *option = (float)newval * scale; |
| 2180 | | } |
| 2181 | | if (str != NULL) |
| 2182 | | { |
| 2183 | | strprintf(*str, fmt, *option); |
| 2184 | | } |
| 2185 | | |
| 2186 | | return floor(*option / scale + 0.5f); |
| 2187 | | } |
| 2188 | | |
| 2189 | | static INT32 slider_shadow_mask_alpha(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2190 | | { |
| 2191 | | return slider_set(&(((hlsl_options*)arg)->shadow_mask_alpha), 0.01f, "%2.2f", str, newval); |
| 2192 | | } |
| 2193 | | |
| 2194 | | static INT32 slider_shadow_mask_x_count(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2195 | | { |
| 2196 | | hlsl_options *options = (hlsl_options*)arg; |
| 2197 | | if (newval != SLIDER_NOCHANGE) |
| 2198 | | { |
| 2199 | | options->shadow_mask_count_x = newval; |
| 2200 | | } |
| 2201 | | if (str != NULL) |
| 2202 | | { |
| 2203 | | strprintf(*str, "%d", options->shadow_mask_count_x); |
| 2204 | | } |
| 2205 | | options->params_dirty = true; |
| 2206 | | |
| 2207 | | return options->shadow_mask_count_x; |
| 2208 | | } |
| 2209 | | |
| 2210 | | static INT32 slider_shadow_mask_y_count(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2211 | | { |
| 2212 | | hlsl_options *options = (hlsl_options*)arg; |
| 2213 | | if (newval != SLIDER_NOCHANGE) |
| 2214 | | { |
| 2215 | | options->shadow_mask_count_y = newval; |
| 2216 | | } |
| 2217 | | if (str != NULL) |
| 2218 | | { |
| 2219 | | strprintf(*str, "%d", options->shadow_mask_count_y); |
| 2220 | | } |
| 2221 | | options->params_dirty = true; |
| 2222 | | |
| 2223 | | return options->shadow_mask_count_y; |
| 2224 | | } |
| 2225 | | |
| 2226 | | static INT32 slider_shadow_mask_usize(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2227 | | { |
| 2228 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2229 | | return slider_set(&(((hlsl_options*)arg)->shadow_mask_u_size), 1.0f / 32.0f, "%2.5f", str, newval); |
| 2230 | | } |
| 2231 | | |
| 2232 | | static INT32 slider_shadow_mask_vsize(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2233 | | { |
| 2234 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2235 | | return slider_set(&(((hlsl_options*)arg)->shadow_mask_v_size), 1.0f / 32.0f, "%2.5f", str, newval); |
| 2236 | | } |
| 2237 | | |
| 2238 | | static INT32 slider_shadow_mask_uoffset(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2239 | | { |
| 2240 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2241 | | return slider_set(&(((hlsl_options*)arg)->shadow_mask_u_offset), 0.01f, "%2.2f", str, newval); |
| 2242 | | } |
| 2243 | | |
| 2244 | | static INT32 slider_shadow_mask_voffset(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2245 | | { |
| 2246 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2247 | | return slider_set(&(((hlsl_options*)arg)->shadow_mask_v_offset), 0.01f, "%2.2f", str, newval); |
| 2248 | | } |
| 2249 | | |
| 2250 | | static INT32 slider_curvature(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2251 | | { |
| 2252 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2253 | | return slider_set(&(((hlsl_options*)arg)->curvature), 0.01f, "%2.2f", str, newval); |
| 2254 | | } |
| 2255 | | |
| 2256 | | static INT32 slider_round_corner(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2257 | | { |
| 2258 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2259 | | return slider_set(&(((hlsl_options*)arg)->round_corner), 0.01f, "%2.2f", str, newval); |
| 2260 | | } |
| 2261 | | |
| 2262 | | static INT32 slider_smooth_border(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2263 | | { |
| 2264 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2265 | | return slider_set(&(((hlsl_options*)arg)->smooth_border), 0.01f, "%2.2f", str, newval); |
| 2266 | | } |
| 2267 | | |
| 2268 | | static INT32 slider_reflection(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2269 | | { |
| 2270 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2271 | | return slider_set(&(((hlsl_options*)arg)->reflection), 0.01f, "%2.2f", str, newval); |
| 2272 | | } |
| 2273 | | |
| 2274 | | static INT32 slider_vignetting(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2275 | | { |
| 2276 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2277 | | return slider_set(&(((hlsl_options*)arg)->vignetting), 0.01f, "%2.2f", str, newval); |
| 2278 | | } |
| 2279 | | |
| 2280 | | static INT32 slider_scanline_alpha(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2281 | | { |
| 2282 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2283 | | return slider_set(&(((hlsl_options*)arg)->scanline_alpha), 0.01f, "%2.2f", str, newval); |
| 2284 | | } |
| 2285 | | |
| 2286 | | static INT32 slider_scanline_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2287 | | { |
| 2288 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2289 | | return slider_set(&(((hlsl_options*)arg)->scanline_scale), 0.05f, "%2.2f", str, newval); |
| 2290 | | } |
| 2291 | | |
| 2292 | | static INT32 slider_scanline_height(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2293 | | { |
| 2294 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2295 | | return slider_set(&(((hlsl_options*)arg)->scanline_height), 0.05f, "%2.2f", str, newval); |
| 2296 | | } |
| 2297 | | |
| 2298 | | static INT32 slider_scanline_bright_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2299 | | { |
| 2300 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2301 | | return slider_set(&(((hlsl_options*)arg)->scanline_bright_scale), 0.05f, "%2.2f", str, newval); |
| 2302 | | } |
| 2303 | | |
| 2304 | | static INT32 slider_scanline_bright_offset(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2305 | | { |
| 2306 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2307 | | return slider_set(&(((hlsl_options*)arg)->scanline_bright_offset), 0.05f, "%2.2f", str, newval); |
| 2308 | | } |
| 2309 | | |
| 2310 | | static INT32 slider_scanline_offset(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2311 | | { |
| 2312 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2313 | | return slider_set(&(((hlsl_options*)arg)->scanline_offset), 0.05f, "%2.2f", str, newval); |
| 2314 | | } |
| 2315 | | |
| 2316 | | static INT32 slider_defocus_x(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2317 | | { |
| 2318 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2319 | | return slider_set(&(((hlsl_options*)arg)->defocus[0]), 0.5f, "%2.1f", str, newval); |
| 2320 | | } |
| 2321 | | |
| 2322 | | static INT32 slider_defocus_y(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2323 | | { |
| 2324 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2325 | | return slider_set(&(((hlsl_options*)arg)->defocus[1]), 0.5f, "%2.1f", str, newval); |
| 2326 | | } |
| 2327 | | |
| 2328 | | static INT32 slider_red_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2329 | | { |
| 2330 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2331 | | return slider_set(&(((hlsl_options*)arg)->converge_x[0]), 0.1f, "%3.1f", str, newval); |
| 2332 | | } |
| 2333 | | |
| 2334 | | static INT32 slider_red_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2335 | | { |
| 2336 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2337 | | return slider_set(&(((hlsl_options*)arg)->converge_y[0]), 0.1f, "%3.1f", str, newval); |
| 2338 | | } |
| 2339 | | |
| 2340 | | static INT32 slider_green_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2341 | | { |
| 2342 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2343 | | return slider_set(&(((hlsl_options*)arg)->converge_x[1]), 0.1f, "%3.1f", str, newval); |
| 2344 | | } |
| 2345 | | |
| 2346 | | static INT32 slider_green_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2347 | | { |
| 2348 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2349 | | return slider_set(&(((hlsl_options*)arg)->converge_y[1]), 0.1f, "%3.1f", str, newval); |
| 2350 | | } |
| 2351 | | |
| 2352 | | static INT32 slider_blue_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2353 | | { |
| 2354 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2355 | | return slider_set(&(((hlsl_options*)arg)->converge_x[2]), 0.1f, "%3.1f", str, newval); |
| 2356 | | } |
| 2357 | | |
| 2358 | | static INT32 slider_blue_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2359 | | { |
| 2360 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2361 | | return slider_set(&(((hlsl_options*)arg)->converge_y[2]), 0.1f, "%3.1f", str, newval); |
| 2362 | | } |
| 2363 | | |
| 2364 | | static INT32 slider_red_radial_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2365 | | { |
| 2366 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2367 | | return slider_set(&(((hlsl_options*)arg)->radial_converge_x[0]), 0.1f, "%3.1f", str, newval); |
| 2368 | | } |
| 2369 | | |
| 2370 | | static INT32 slider_red_radial_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2371 | | { |
| 2372 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2373 | | return slider_set(&(((hlsl_options*)arg)->radial_converge_y[0]), 0.1f, "%3.1f", str, newval); |
| 2374 | | } |
| 2375 | | |
| 2376 | | static INT32 slider_green_radial_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2377 | | { |
| 2378 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2379 | | return slider_set(&(((hlsl_options*)arg)->radial_converge_x[1]), 0.1f, "%3.1f", str, newval); |
| 2380 | | } |
| 2381 | | |
| 2382 | | static INT32 slider_green_radial_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2383 | | { |
| 2384 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2385 | | return slider_set(&(((hlsl_options*)arg)->radial_converge_y[1]), 0.1f, "%3.1f", str, newval); |
| 2386 | | } |
| 2387 | | |
| 2388 | | static INT32 slider_blue_radial_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2389 | | { |
| 2390 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2391 | | return slider_set(&(((hlsl_options*)arg)->radial_converge_x[2]), 0.1f, "%3.1f", str, newval); |
| 2392 | | } |
| 2393 | | |
| 2394 | | static INT32 slider_blue_radial_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2395 | | { |
| 2396 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2397 | | return slider_set(&(((hlsl_options*)arg)->radial_converge_y[2]), 0.1f, "%3.1f", str, newval); |
| 2398 | | } |
| 2399 | | |
| 2400 | | static INT32 slider_red_from_r(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2401 | | { |
| 2402 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2403 | | return slider_set(&(((hlsl_options*)arg)->red_ratio[0]), 0.005f, "%2.3f", str, newval); |
| 2404 | | } |
| 2405 | | |
| 2406 | | static INT32 slider_red_from_g(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2407 | | { |
| 2408 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2409 | | return slider_set(&(((hlsl_options*)arg)->red_ratio[1]), 0.005f, "%2.3f", str, newval); |
| 2410 | | } |
| 2411 | | |
| 2412 | | static INT32 slider_red_from_b(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2413 | | { |
| 2414 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2415 | | return slider_set(&(((hlsl_options*)arg)->red_ratio[2]), 0.005f, "%2.3f", str, newval); |
| 2416 | | } |
| 2417 | | |
| 2418 | | static INT32 slider_green_from_r(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2419 | | { |
| 2420 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2421 | | return slider_set(&(((hlsl_options*)arg)->grn_ratio[0]), 0.005f, "%2.3f", str, newval); |
| 2422 | | } |
| 2423 | | |
| 2424 | | static INT32 slider_green_from_g(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2425 | | { |
| 2426 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2427 | | return slider_set(&(((hlsl_options*)arg)->grn_ratio[1]), 0.005f, "%2.3f", str, newval); |
| 2428 | | } |
| 2429 | | |
| 2430 | | static INT32 slider_green_from_b(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2431 | | { |
| 2432 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2433 | | return slider_set(&(((hlsl_options*)arg)->grn_ratio[2]), 0.005f, "%2.3f", str, newval); |
| 2434 | | } |
| 2435 | | |
| 2436 | | static INT32 slider_blue_from_r(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2437 | | { |
| 2438 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2439 | | return slider_set(&(((hlsl_options*)arg)->blu_ratio[0]), 0.005f, "%2.3f", str, newval); |
| 2440 | | } |
| 2441 | | |
| 2442 | | static INT32 slider_blue_from_g(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2443 | | { |
| 2444 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2445 | | return slider_set(&(((hlsl_options*)arg)->blu_ratio[1]), 0.005f, "%2.3f", str, newval); |
| 2446 | | } |
| 2447 | | |
| 2448 | | static INT32 slider_blue_from_b(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2449 | | { |
| 2450 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2451 | | return slider_set(&(((hlsl_options*)arg)->blu_ratio[2]), 0.005f, "%2.3f", str, newval); |
| 2452 | | } |
| 2453 | | |
| 2454 | | static INT32 slider_red_offset(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2455 | | { |
| 2456 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2457 | | return slider_set(&(((hlsl_options*)arg)->offset[0]), 0.01f, "%2.2f", str, newval); |
| 2458 | | } |
| 2459 | | |
| 2460 | | static INT32 slider_green_offset(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2461 | | { |
| 2462 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2463 | | return slider_set(&(((hlsl_options*)arg)->offset[1]), 0.01f, "%2.2f", str, newval); |
| 2464 | | } |
| 2465 | | |
| 2466 | | static INT32 slider_blue_offset(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2467 | | { |
| 2468 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2469 | | return slider_set(&(((hlsl_options*)arg)->offset[2]), 0.01f, "%2.2f", str, newval); |
| 2470 | | } |
| 2471 | | |
| 2472 | | static INT32 slider_red_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2473 | | { |
| 2474 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2475 | | return slider_set(&(((hlsl_options*)arg)->scale[0]), 0.01f, "%2.2f", str, newval); |
| 2476 | | } |
| 2477 | | |
| 2478 | | static INT32 slider_green_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2479 | | { |
| 2480 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2481 | | return slider_set(&(((hlsl_options*)arg)->scale[1]), 0.01f, "%2.2f", str, newval); |
| 2482 | | } |
| 2483 | | |
| 2484 | | static INT32 slider_blue_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2485 | | { |
| 2486 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2487 | | return slider_set(&(((hlsl_options*)arg)->scale[2]), 0.01f, "%2.2f", str, newval); |
| 2488 | | } |
| 2489 | | |
| 2490 | | static INT32 slider_red_power(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2491 | | { |
| 2492 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2493 | | return slider_set(&(((hlsl_options*)arg)->power[0]), 0.05f, "%2.2f", str, newval); |
| 2494 | | } |
| 2495 | | |
| 2496 | | static INT32 slider_green_power(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2497 | | { |
| 2498 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2499 | | return slider_set(&(((hlsl_options*)arg)->power[1]), 0.05f, "%2.2f", str, newval); |
| 2500 | | } |
| 2501 | | |
| 2502 | | static INT32 slider_blue_power(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2503 | | { |
| 2504 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2505 | | return slider_set(&(((hlsl_options*)arg)->power[2]), 0.05f, "%2.2f", str, newval); |
| 2506 | | } |
| 2507 | | |
| 2508 | | static INT32 slider_red_floor(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2509 | | { |
| 2510 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2511 | | return slider_set(&(((hlsl_options*)arg)->floor[0]), 0.01f, "%2.2f", str, newval); |
| 2512 | | } |
| 2513 | | |
| 2514 | | static INT32 slider_green_floor(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2515 | | { |
| 2516 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2517 | | return slider_set(&(((hlsl_options*)arg)->floor[1]), 0.01f, "%2.2f", str, newval); |
| 2518 | | } |
| 2519 | | |
| 2520 | | static INT32 slider_blue_floor(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2521 | | { |
| 2522 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2523 | | return slider_set(&(((hlsl_options*)arg)->floor[2]), 0.01f, "%2.2f", str, newval); |
| 2524 | | } |
| 2525 | | |
| 2526 | | static INT32 slider_red_phosphor_life(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2527 | | { |
| 2528 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2529 | | return slider_set(&(((hlsl_options*)arg)->phosphor[0]), 0.01f, "%2.2f", str, newval); |
| 2530 | | } |
| 2531 | | |
| 2532 | | static INT32 slider_green_phosphor_life(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2533 | | { |
| 2534 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2535 | | return slider_set(&(((hlsl_options*)arg)->phosphor[1]), 0.01f, "%2.2f", str, newval); |
| 2536 | | } |
| 2537 | | |
| 2538 | | static INT32 slider_blue_phosphor_life(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2539 | | { |
| 2540 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2541 | | return slider_set(&(((hlsl_options*)arg)->phosphor[2]), 0.01f, "%2.2f", str, newval); |
| 2542 | | } |
| 2543 | | |
| 2544 | | static INT32 slider_saturation(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2545 | | { |
| 2546 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2547 | | return slider_set(&(((hlsl_options*)arg)->saturation), 0.01f, "%2.2f", str, newval); |
| 2548 | | } |
| 2549 | | |
| 2550 | | static INT32 slider_vector_attenuation(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2551 | | { |
| 2552 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2553 | | return slider_set(&(((hlsl_options*)arg)->vector_length_scale), 0.01f, "%1.2f", str, newval); |
| 2554 | | } |
| 2555 | | |
| 2556 | | static INT32 slider_vector_length_max(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2557 | | { |
| 2558 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2559 | | return slider_set(&(((hlsl_options*)arg)->vector_length_ratio), 1.0f, "%4f", str, newval); |
| 2560 | | } |
| 2561 | | |
| 2562 | | static INT32 slider_bloom_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2563 | | { |
| 2564 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2565 | | return slider_set(&(((hlsl_options*)arg)->bloom_scale), 0.001f, "%1.3f", str, newval); |
| 2566 | | } |
| 2567 | | |
| 2568 | | static INT32 slider_bloom_red_overdrive(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2569 | | { |
| 2570 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2571 | | return slider_set(&(((hlsl_options*)arg)->bloom_overdrive[0]), 0.001f, "%1.3f", str, newval); |
| 2572 | | } |
| 2573 | | |
| 2574 | | static INT32 slider_bloom_green_overdrive(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2575 | | { |
| 2576 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2577 | | return slider_set(&(((hlsl_options*)arg)->bloom_overdrive[1]), 0.001f, "%1.3f", str, newval); |
| 2578 | | } |
| 2579 | | |
| 2580 | | static INT32 slider_bloom_blue_overdrive(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2581 | | { |
| 2582 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2583 | | return slider_set(&(((hlsl_options*)arg)->bloom_overdrive[2]), 0.001f, "%1.3f", str, newval); |
| 2584 | | } |
| 2585 | | |
| 2586 | | static INT32 slider_bloom_lvl0_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2587 | | { |
| 2588 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2589 | | return slider_set(&(((hlsl_options*)arg)->bloom_level0_weight), 0.01f, "%1.2f", str, newval); |
| 2590 | | } |
| 2591 | | |
| 2592 | | static INT32 slider_bloom_lvl1_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2593 | | { |
| 2594 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2595 | | return slider_set(&(((hlsl_options*)arg)->bloom_level1_weight), 0.01f, "%1.2f", str, newval); |
| 2596 | | } |
| 2597 | | |
| 2598 | | static INT32 slider_bloom_lvl2_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2599 | | { |
| 2600 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2601 | | return slider_set(&(((hlsl_options*)arg)->bloom_level2_weight), 0.01f, "%1.2f", str, newval); |
| 2602 | | } |
| 2603 | | |
| 2604 | | static INT32 slider_bloom_lvl3_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2605 | | { |
| 2606 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2607 | | return slider_set(&(((hlsl_options*)arg)->bloom_level3_weight), 0.01f, "%1.2f", str, newval); |
| 2608 | | } |
| 2609 | | |
| 2610 | | static INT32 slider_bloom_lvl4_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2611 | | { |
| 2612 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2613 | | return slider_set(&(((hlsl_options*)arg)->bloom_level4_weight), 0.01f, "%1.2f", str, newval); |
| 2614 | | } |
| 2615 | | |
| 2616 | | static INT32 slider_bloom_lvl5_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2617 | | { |
| 2618 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2619 | | return slider_set(&(((hlsl_options*)arg)->bloom_level5_weight), 0.01f, "%1.2f", str, newval); |
| 2620 | | } |
| 2621 | | |
| 2622 | | static INT32 slider_bloom_lvl6_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2623 | | { |
| 2624 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2625 | | return slider_set(&(((hlsl_options*)arg)->bloom_level6_weight), 0.01f, "%1.2f", str, newval); |
| 2626 | | } |
| 2627 | | |
| 2628 | | static INT32 slider_bloom_lvl7_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2629 | | { |
| 2630 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2631 | | return slider_set(&(((hlsl_options*)arg)->bloom_level7_weight), 0.01f, "%1.2f", str, newval); |
| 2632 | | } |
| 2633 | | |
| 2634 | | static INT32 slider_bloom_lvl8_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2635 | | { |
| 2636 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2637 | | return slider_set(&(((hlsl_options*)arg)->bloom_level8_weight), 0.01f, "%1.2f", str, newval); |
| 2638 | | } |
| 2639 | | |
| 2640 | | static INT32 slider_bloom_lvl9_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2641 | | { |
| 2642 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2643 | | return slider_set(&(((hlsl_options*)arg)->bloom_level9_weight), 0.01f, "%1.2f", str, newval); |
| 2644 | | } |
| 2645 | | |
| 2646 | | static INT32 slider_bloom_lvl10_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2647 | | { |
| 2648 | | ((hlsl_options*)arg)->params_dirty = true; |
| 2649 | | return slider_set(&(((hlsl_options*)arg)->bloom_level10_weight), 0.01f, "%1.2f", str, newval); |
| 2650 | | } |
| 2651 | | |
| 2652 | | |
| 2653 | | //============================================================ |
| 2654 | | // init_slider_list |
| 2655 | | //============================================================ |
| 2656 | | |
| 2657 | | shaders::slider_desc shaders::s_sliders[] = |
| 2658 | | { |
| 2659 | | { "Vector Length Attenuation", 0, 80, 100, 1, 2, slider_vector_attenuation }, |
| 2660 | | { "Vector Attenuation Length Limit", 1, 500, 1000, 1, 2, slider_vector_length_max }, |
| 2661 | | { "Shadow Mask Darkness", 0, 0, 100, 1, 7, slider_shadow_mask_alpha }, |
| 2662 | | { "Shadow Mask X Count", 1, 6, 1024, 1, 7, slider_shadow_mask_x_count }, |
| 2663 | | { "Shadow Mask Y Count", 1, 6, 1024, 1, 7, slider_shadow_mask_y_count }, |
| 2664 | | { "Shadow Mask Pixel Count X", 1, 6, 64, 1, 7, slider_shadow_mask_usize }, |
| 2665 | | { "Shadow Mask Pixel Count Y", 1, 6, 64, 1, 7, slider_shadow_mask_vsize }, |
| 2666 | | { "Shadow Mask Offset X", -100, 0, 100, 1, 7, slider_shadow_mask_uoffset }, |
| 2667 | | { "Shadow Mask Offset Y", -100, 0, 100, 1, 7, slider_shadow_mask_voffset }, |
| 2668 | | { "Screen Curvature", 0, 0, 100, 1, 7, slider_curvature }, |
| 2669 | | { "Screen Round Corner", 0, 0, 100, 1, 7, slider_round_corner }, |
| 2670 | | { "Screen Smooth Border", 0, 0, 100, 1, 7, slider_smooth_border }, |
| 2671 | | { "Screen Reflection", 0, 0, 100, 1, 7, slider_reflection }, |
| 2672 | | { "Image Vignetting", 0, 0, 100, 1, 7, slider_vignetting }, |
| 2673 | | { "Scanline Darkness", 0, 100, 100, 1, 1, slider_scanline_alpha }, |
| 2674 | | { "Scanline Screen Height", 1, 20, 80, 1, 1, slider_scanline_scale }, |
| 2675 | | { "Scanline Indiv. Height", 1, 20, 80, 1, 1, slider_scanline_height }, |
| 2676 | | { "Scanline Brightness", 0, 20, 40, 1, 1, slider_scanline_bright_scale }, |
| 2677 | | { "Scanline Brightness Overdrive", 0, 0, 20, 1, 1, slider_scanline_bright_offset }, |
| 2678 | | { "Scanline Jitter", 0, 0, 40, 1, 1, slider_scanline_offset }, |
| 2679 | | { "Defocus X", 0, 0, 64, 1, 3, slider_defocus_x }, |
| 2680 | | { "Defocus Y", 0, 0, 64, 1, 3, slider_defocus_y }, |
| 2681 | | { "Red Position Offset X", -1500, 3, 1500, 1, 3, slider_red_converge_x }, |
| 2682 | | { "Red Position Offset Y", -1500, 0, 1500, 1, 3, slider_red_converge_y }, |
| 2683 | | { "Green Position Offset X", -1500, 0, 1500, 1, 3, slider_green_converge_x }, |
| 2684 | | { "Green Position Offset Y", -1500, 3, 1500, 1, 3, slider_green_converge_y }, |
| 2685 | | { "Blue Position Offset X", -1500, 3, 1500, 1, 3, slider_blue_converge_x }, |
| 2686 | | { "Blue Position Offset Y", -1500, 3, 1500, 1, 3, slider_blue_converge_y }, |
| 2687 | | { "Red Convergence X", -1500, 0, 1500, 1, 3, slider_red_radial_converge_x }, |
| 2688 | | { "Red Convergence Y", -1500, 0, 1500, 1, 3, slider_red_radial_converge_y }, |
| 2689 | | { "Green Convergence X", -1500, 0, 1500, 1, 3, slider_green_radial_converge_x }, |
| 2690 | | { "Green Convergence Y", -1500, 0, 1500, 1, 3, slider_green_radial_converge_y }, |
| 2691 | | { "Blue Convergence X", -1500, 0, 1500, 1, 3, slider_blue_radial_converge_x }, |
| 2692 | | { "Blue Convergence Y", -1500, 0, 1500, 1, 3, slider_blue_radial_converge_y }, |
| 2693 | | { "Red Output from Red Input", -400, 0, 400, 5, 7, slider_red_from_r }, |
| 2694 | | { "Red Output from Green Input", -400, 0, 400, 5, 7, slider_red_from_g }, |
| 2695 | | { "Red Output from Blue Input", -400, 0, 400, 5, 7, slider_red_from_b }, |
| 2696 | | { "Green Output from Red Input", -400, 0, 400, 5, 7, slider_green_from_r }, |
| 2697 | | { "Green Output from Green Input", -400, 0, 400, 5, 7, slider_green_from_g }, |
| 2698 | | { "Green Output from Blue Input", -400, 0, 400, 5, 7, slider_green_from_b }, |
| 2699 | | { "Blue Output from Red Input", -400, 0, 400, 5, 7, slider_blue_from_r }, |
| 2700 | | { "Blue Output from Green Input", -400, 0, 400, 5, 7, slider_blue_from_g }, |
| 2701 | | { "Blue Output from Blue Input", -400, 0, 400, 5, 7, slider_blue_from_b }, |
| 2702 | | { "Saturation", 0, 140, 400, 1, 7, slider_saturation }, |
| 2703 | | { "Red DC Offset", -100, 0, 100, 1, 7, slider_red_offset }, |
| 2704 | | { "Green DC Offset", -100, 0, 100, 1, 7, slider_green_offset }, |
| 2705 | | { "Blue DC Offset", -100, 0, 100, 1, 7, slider_blue_offset }, |
| 2706 | | { "Red Scale", -200, 95, 200, 1, 7, slider_red_scale }, |
| 2707 | | { "Green Scale", -200, 95, 200, 1, 7, slider_green_scale }, |
| 2708 | | { "Blue Scale", -200, 95, 200, 1, 7, slider_blue_scale }, |
| 2709 | | { "Red Gamma", -80, 16, 80, 1, 7, slider_red_power }, |
| 2710 | | { "Green Gamma", -80, 16, 80, 1, 7, slider_green_power }, |
| 2711 | | { "Blue Gamma", -80, 16, 80, 1, 7, slider_blue_power }, |
| 2712 | | { "Red Floor", 0, 5, 100, 1, 7, slider_red_floor }, |
| 2713 | | { "Green Floor", 0, 5, 100, 1, 7, slider_green_floor }, |
| 2714 | | { "Blue Floor", 0, 5, 100, 1, 7, slider_blue_floor }, |
| 2715 | | { "Red Phosphor Life", 0, 40, 100, 1, 7, slider_red_phosphor_life }, |
| 2716 | | { "Green Phosphor Life", 0, 40, 100, 1, 7, slider_green_phosphor_life }, |
| 2717 | | { "Blue Phosphor Life", 0, 40, 100, 1, 7, slider_blue_phosphor_life }, |
| 2718 | | { "Bloom Scale", 0, 250, 2000, 5, 7, slider_bloom_scale }, |
| 2719 | | { "Bloom Red Overdrive", 0, 250, 2000, 5, 7, slider_bloom_red_overdrive }, |
| 2720 | | { "Bloom Green Overdrive", 0, 250, 2000, 5, 7, slider_bloom_green_overdrive }, |
| 2721 | | { "Bloom Blue Overdrive", 0, 250, 2000, 5, 7, slider_bloom_blue_overdrive }, |
| 2722 | | { "Bloom Level 0 Scale", 0, 100, 100, 1, 7, slider_bloom_lvl0_scale }, |
| 2723 | | { "Bloom Level 1 Scale", 0, 21, 100, 1, 7, slider_bloom_lvl1_scale }, |
| 2724 | | { "Bloom Level 2 Scale", 0, 19, 100, 1, 7, slider_bloom_lvl2_scale }, |
| 2725 | | { "Bloom Level 3 Scale", 0, 17, 100, 1, 7, slider_bloom_lvl3_scale }, |
| 2726 | | { "Bloom Level 4 Scale", 0, 15, 100, 1, 7, slider_bloom_lvl4_scale }, |
| 2727 | | { "Bloom Level 5 Scale", 0, 14, 100, 1, 7, slider_bloom_lvl5_scale }, |
| 2728 | | { "Bloom Level 6 Scale", 0, 13, 100, 1, 7, slider_bloom_lvl6_scale }, |
| 2729 | | { "Bloom Level 7 Scale", 0, 12, 100, 1, 7, slider_bloom_lvl7_scale }, |
| 2730 | | { "Bloom Level 8 Scale", 0, 11, 100, 1, 7, slider_bloom_lvl8_scale }, |
| 2731 | | { "Bloom Level 9 Scale", 0, 10, 100, 1, 7, slider_bloom_lvl9_scale }, |
| 2732 | | { "Bloom Level 10 Scale", 0, 9, 100, 1, 7, slider_bloom_lvl10_scale }, |
| 2733 | | { NULL, 0, 0, 0, 0, 0, NULL }, |
| 2734 | | }; |
| 2735 | | |
| 2736 | | slider_state *shaders::init_slider_list() |
| 2737 | | { |
| 2738 | | if (!master_enable || !d3dintf->post_fx_available) |
| 2739 | | { |
| 2740 | | g_slider_list = NULL; |
| 2741 | | return NULL; |
| 2742 | | } |
| 2743 | | |
| 2744 | | slider_state *listhead = NULL; |
| 2745 | | slider_state **tailptr = &listhead; |
| 2746 | | |
| 2747 | | for (int index = 0; s_sliders[index].name != NULL; index++) |
| 2748 | | { |
| 2749 | | slider_desc *slider = &s_sliders[index]; |
| 2750 | | |
| 2751 | | int screen_type = machine->first_screen()->screen_type(); |
| 2752 | | if ((screen_type == SCREEN_TYPE_VECTOR && (slider->screen_type & SLIDER_SCREEN_TYPE_VECTOR) == SLIDER_SCREEN_TYPE_VECTOR) || |
| 2753 | | (screen_type == SCREEN_TYPE_RASTER && (slider->screen_type & SLIDER_SCREEN_TYPE_RASTER) == SLIDER_SCREEN_TYPE_RASTER) || |
| 2754 | | (screen_type == SCREEN_TYPE_LCD && (slider->screen_type & SLIDER_SCREEN_TYPE_LCD) == SLIDER_SCREEN_TYPE_LCD)) |
| 2755 | | { |
| 2756 | | *tailptr = slider_alloc(*machine, slider->name, slider->minval, slider->defval, slider->maxval, slider->step, slider->adjustor, (void*)options); |
| 2757 | | tailptr = &(*tailptr)->next; |
| 2758 | | } |
| 2759 | | } |
| 2760 | | |
| 2761 | | return listhead; |
| 2762 | | } |
| 2763 | | |
| 2764 | | |
| 2765 | | //============================================================ |
| 2766 | | // uniform functions |
| 2767 | | //============================================================ |
| 2768 | | |
| 2769 | | uniform::uniform(effect *shader, const char *name, uniform_type type, int id) |
| 2770 | | { |
| 2771 | | m_shader = shader; |
| 2772 | | m_type = type; |
| 2773 | | m_next = NULL; |
| 2774 | | m_handle = m_shader->get_parameter(NULL, name); |
| 2775 | | m_ival = 0; |
| 2776 | | memset(m_vec, 0, sizeof(float) * 4); |
| 2777 | | m_mval = NULL; |
| 2778 | | m_texture = NULL; |
| 2779 | | m_id = id; |
| 2780 | | |
| 2781 | | switch (type) |
| 2782 | | { |
| 2783 | | case UT_INT: |
| 2784 | | case UT_FLOAT: |
| 2785 | | case UT_MATRIX: |
| 2786 | | case UT_SAMPLER: |
| 2787 | | m_count = 1; |
| 2788 | | break; |
| 2789 | | case UT_VEC2: |
| 2790 | | m_count = 2; |
| 2791 | | break; |
| 2792 | | case UT_VEC3: |
| 2793 | | m_count = 3; |
| 2794 | | break; |
| 2795 | | case UT_VEC4: |
| 2796 | | m_count = 4; |
| 2797 | | break; |
| 2798 | | default: |
| 2799 | | m_count = 1; |
| 2800 | | break; |
| 2801 | | } |
| 2802 | | } |
| 2803 | | |
| 2804 | | void uniform::set_next(uniform *next) |
| 2805 | | { |
| 2806 | | m_next = next; |
| 2807 | | } |
| 2808 | | |
| 2809 | | void uniform::update() |
| 2810 | | { |
| 2811 | | if (m_id >= CU_COUNT) |
| 2812 | | { |
| 2813 | | return; |
| 2814 | | } |
| 2815 | | |
| 2816 | | shaders *shadersys = m_shader->m_shaders; |
| 2817 | | hlsl_options *options = shadersys->options; |
| 2818 | | renderer *d3d = shadersys->d3d; |
| 2819 | | |
| 2820 | | switch (m_id) |
| 2821 | | { |
| 2822 | | case CU_SCREEN_DIMS: |
| 2823 | | { |
| 2824 | | vec2f screendims = d3d->get_dims(); |
| 2825 | | m_shader->set_vector("ScreenDims", 2, &screendims.c.x); |
| 2826 | | break; |
| 2827 | | } |
| 2828 | | case CU_SOURCE_DIMS: |
| 2829 | | { |
| 2830 | | vec2f sourcedims = shadersys->curr_texture->get_rawdims(); |
| 2831 | | m_shader->set_vector("SourceDims", 2, &sourcedims.c.x); |
| 2832 | | break; |
| 2833 | | } |
| 2834 | | case CU_SOURCE_RECT: |
| 2835 | | { |
| 2836 | | vec2f delta = shadersys->curr_texture->get_uvstop() - shadersys->curr_texture->get_uvstart(); |
| 2837 | | m_shader->set_vector("SourceRect", 2, &delta.c.x); |
| 2838 | | break; |
| 2839 | | } |
| 2840 | | case CU_TARGET_DIMS: |
| 2841 | | { |
| 2842 | | if (shadersys->curr_render_target == NULL) |
| 2843 | | { |
| 2844 | | float targetdims[2] = { 0.0f, 0.0f }; |
| 2845 | | m_shader->set_vector("TargetDims", 2, targetdims); |
| 2846 | | } |
| 2847 | | else |
| 2848 | | { |
| 2849 | | float targetdims[2] = { shadersys->curr_render_target->target_width, shadersys->curr_render_target->target_height }; |
| 2850 | | m_shader->set_vector("TargetDims", 2, targetdims); |
| 2851 | | } |
| 2852 | | break; |
| 2853 | | } |
| 2854 | | case CU_QUAD_DIMS: |
| 2855 | | { |
| 2856 | | float quaddims[2] = { shadersys->curr_poly->get_prim_width(), shadersys->curr_poly->get_prim_height() }; |
| 2857 | | m_shader->set_vector("QuadDims", 2, quaddims); |
| 2858 | | break; |
| 2859 | | } |
| 2860 | | |
| 2861 | | case CU_NTSC_CCFREQ: |
| 2862 | | m_shader->set_float("CCValue", options->yiq_cc); |
| 2863 | | break; |
| 2864 | | case CU_NTSC_A: |
| 2865 | | m_shader->set_float("AValue", options->yiq_a); |
| 2866 | | break; |
| 2867 | | case CU_NTSC_B: |
| 2868 | | m_shader->set_float("BValue", options->yiq_b); |
| 2869 | | break; |
| 2870 | | case CU_NTSC_O: |
| 2871 | | m_shader->set_float("OValue", options->yiq_o); |
| 2872 | | break; |
| 2873 | | case CU_NTSC_P: |
| 2874 | | m_shader->set_float("PValue", options->yiq_p); |
| 2875 | | break; |
| 2876 | | case CU_NTSC_NOTCH: |
| 2877 | | m_shader->set_float("NotchHalfWidth", options->yiq_n); |
| 2878 | | break; |
| 2879 | | case CU_NTSC_YFREQ: |
| 2880 | | m_shader->set_float("YFreqResponse", options->yiq_y); |
| 2881 | | break; |
| 2882 | | case CU_NTSC_IFREQ: |
| 2883 | | m_shader->set_float("IFreqResponse", options->yiq_i); |
| 2884 | | break; |
| 2885 | | case CU_NTSC_QFREQ: |
| 2886 | | m_shader->set_float("QFreqResponse", options->yiq_q); |
| 2887 | | break; |
| 2888 | | case CU_NTSC_HTIME: |
| 2889 | | m_shader->set_float("ScanTime", options->yiq_scan_time); |
| 2890 | | break; |
| 2891 | | case CU_NTSC_ENABLE: |
| 2892 | | m_shader->set_float("YIQEnable", options->yiq_enable ? 1.0f : 0.0f); |
| 2893 | | break; |
| 2894 | | |
| 2895 | | case CU_COLOR_RED_RATIOS: |
| 2896 | | m_shader->set_vector("RedRatios", 3, options->red_ratio); |
| 2897 | | break; |
| 2898 | | case CU_COLOR_GRN_RATIOS: |
| 2899 | | m_shader->set_vector("GrnRatios", 3, options->grn_ratio); |
| 2900 | | break; |
| 2901 | | case CU_COLOR_BLU_RATIOS: |
| 2902 | | m_shader->set_vector("BluRatios", 3, options->blu_ratio); |
| 2903 | | break; |
| 2904 | | case CU_COLOR_OFFSET: |
| 2905 | | m_shader->set_vector("Offset", 3, options->offset); |
| 2906 | | break; |
| 2907 | | case CU_COLOR_SCALE: |
| 2908 | | m_shader->set_vector("Scale", 3, options->scale); |
| 2909 | | break; |
| 2910 | | case CU_COLOR_SATURATION: |
| 2911 | | m_shader->set_float("Saturation", options->saturation); |
| 2912 | | break; |
| 2913 | | |
| 2914 | | case CU_CONVERGE_LINEAR_X: |
| 2915 | | m_shader->set_vector("ConvergeX", 3, options->converge_x); |
| 2916 | | break; |
| 2917 | | case CU_CONVERGE_LINEAR_Y: |
| 2918 | | m_shader->set_vector("ConvergeY", 3, options->converge_y); |
| 2919 | | break; |
| 2920 | | case CU_CONVERGE_RADIAL_X: |
| 2921 | | m_shader->set_vector("RadialConvergeX", 3, options->radial_converge_x); |
| 2922 | | break; |
| 2923 | | case CU_CONVERGE_RADIAL_Y: |
| 2924 | | m_shader->set_vector("RadialConvergeY", 3, options->radial_converge_y); |
| 2925 | | break; |
| 2926 | | |
| 2927 | | case CU_FOCUS_SIZE: |
| 2928 | | m_shader->set_vector("Defocus", 2, &options->defocus[0]); |
| 2929 | | break; |
| 2930 | | |
| 2931 | | case CU_PHOSPHOR_LIFE: |
| 2932 | | m_shader->set_vector("Phosphor", 3, options->phosphor); |
| 2933 | | break; |
| 2934 | | |
| 2935 | | case CU_POST_REFLECTION: |
| 2936 | | m_shader->set_float("ReflectionAmount", options->reflection); |
| 2937 | | break; |
| 2938 | | case CU_POST_VIGNETTING: |
| 2939 | | m_shader->set_float("VignettingAmount", options->vignetting); |
| 2940 | | break; |
| 2941 | | case CU_POST_CURVATURE: |
| 2942 | | m_shader->set_float("CurvatureAmount", options->curvature); |
| 2943 | | break; |
| 2944 | | case CU_POST_ROUND_CORNER: |
| 2945 | | m_shader->set_float("RoundCornerAmount", options->round_corner); |
| 2946 | | break; |
| 2947 | | case CU_POST_SMOOTH_BORDER: |
| 2948 | | m_shader->set_float("SmoothBorderAmount", options->smooth_border); |
| 2949 | | break; |
| 2950 | | case CU_POST_SHADOW_ALPHA: |
| 2951 | | m_shader->set_float("ShadowAlpha", shadersys->shadow_texture == NULL ? 0.0f : options->shadow_mask_alpha); |
| 2952 | | break; |
| 2953 | | case CU_POST_SHADOW_COUNT: |
| 2954 | | { |
| 2955 | | float shadowcount[2] = { options->shadow_mask_count_x, options->shadow_mask_count_y }; |
| 2956 | | m_shader->set_vector("ShadowCount", 2, shadowcount); |
| 2957 | | break; |
| 2958 | | } |
| 2959 | | case CU_POST_SHADOW_UV: |
| 2960 | | { |
| 2961 | | float shadowuv[2] = { options->shadow_mask_u_size, options->shadow_mask_v_size }; |
| 2962 | | m_shader->set_vector("ShadowUV", 2, shadowuv); |
| 2963 | | break; |
| 2964 | | } |
| 2965 | | case CU_POST_SHADOW_UV_OFFSET: |
| 2966 | | { |
| 2967 | | float shadowuv[2] = { options->shadow_mask_u_offset, options->shadow_mask_v_offset }; |
| 2968 | | m_shader->set_vector("ShadowUVOffset", 2, shadowuv); |
| 2969 | | break; |
| 2970 | | } |
| 2971 | | case CU_POST_SHADOW_DIMS: |
| 2972 | | { |
| 2973 | | vec2f shadow_dims; |
| 2974 | | |
| 2975 | | if (shadersys->shadow_texture) |
| 2976 | | { |
| 2977 | | shadow_dims = shadersys->shadow_texture->get_rawdims(); |
| 2978 | | } |
| 2979 | | else |
| 2980 | | { |
| 2981 | | shadow_dims.c.x = 1.0f; |
| 2982 | | shadow_dims.c.y = 1.0f; |
| 2983 | | } |
| 2984 | | |
| 2985 | | m_shader->set_vector("ShadowDims", 2, &shadow_dims.c.x); |
| 2986 | | break; |
| 2987 | | } |
| 2988 | | case CU_POST_SCANLINE_ALPHA: |
| 2989 | | m_shader->set_float("ScanlineAlpha", options->scanline_alpha); |
| 2990 | | break; |
| 2991 | | case CU_POST_SCANLINE_SCALE: |
| 2992 | | m_shader->set_float("ScanlineScale", options->scanline_scale); |
| 2993 | | break; |
| 2994 | | case CU_POST_SCANLINE_HEIGHT: |
| 2995 | | m_shader->set_float("ScanlineHeight", options->scanline_height); |
| 2996 | | break; |
| 2997 | | case CU_POST_SCANLINE_BRIGHT_SCALE: |
| 2998 | | m_shader->set_float("ScanlineBrightScale", options->scanline_bright_scale); |
| 2999 | | break; |
| 3000 | | case CU_POST_SCANLINE_BRIGHT_OFFSET: |
| 3001 | | m_shader->set_float("ScanlineBrightOffset", options->scanline_bright_offset); |
| 3002 | | break; |
| 3003 | | case CU_POST_POWER: |
| 3004 | | m_shader->set_vector("Power", 3, options->power); |
| 3005 | | break; |
| 3006 | | case CU_POST_FLOOR: |
| 3007 | | m_shader->set_vector("Floor", 3, options->floor); |
| 3008 | | break; |
| 3009 | | |
| 3010 | | case CU_BLOOM_RESCALE: |
| 3011 | | m_shader->set_float("BloomRescale", options->bloom_scale); |
| 3012 | | break; |
| 3013 | | case CU_BLOOM_LVL0123_WEIGHTS: |
| 3014 | | { |
| 3015 | | float weight0123[4] = { options->bloom_level0_weight, options->bloom_level1_weight, options->bloom_level2_weight, options->bloom_level3_weight }; |
| 3016 | | m_shader->set_vector("Level0123Weight", 4, weight0123); |
| 3017 | | break; |
| 3018 | | } |
| 3019 | | case CU_BLOOM_LVL4567_WEIGHTS: |
| 3020 | | { |
| 3021 | | float weight4567[4] = { options->bloom_level4_weight, options->bloom_level5_weight, options->bloom_level6_weight, options->bloom_level7_weight }; |
| 3022 | | m_shader->set_vector("Level4567Weight", 4, weight4567); |
| 3023 | | break; |
| 3024 | | } |
| 3025 | | case CU_BLOOM_LVL89A_WEIGHTS: |
| 3026 | | { |
| 3027 | | float weight89A[3] = { options->bloom_level8_weight, options->bloom_level9_weight, options->bloom_level10_weight }; |
| 3028 | | m_shader->set_vector("Level89AWeight", 3, weight89A); |
| 3029 | | break; |
| 3030 | | } |
| 3031 | | } |
| 3032 | | } |
| 3033 | | |
| 3034 | | void uniform::set(float x, float y, float z, float w) |
| 3035 | | { |
| 3036 | | m_vec[0] = x; |
| 3037 | | m_vec[1] = y; |
| 3038 | | m_vec[2] = z; |
| 3039 | | m_vec[3] = w; |
| 3040 | | } |
| 3041 | | |
| 3042 | | void uniform::set(float x, float y, float z) |
| 3043 | | { |
| 3044 | | m_vec[0] = x; |
| 3045 | | m_vec[1] = y; |
| 3046 | | m_vec[2] = z; |
| 3047 | | } |
| 3048 | | |
| 3049 | | void uniform::set(float x, float y) |
| 3050 | | { |
| 3051 | | m_vec[0] = x; |
| 3052 | | m_vec[1] = y; |
| 3053 | | } |
| 3054 | | |
| 3055 | | void uniform::set(float x) |
| 3056 | | { |
| 3057 | | m_vec[0] = x; |
| 3058 | | } |
| 3059 | | |
| 3060 | | void uniform::set(int x) |
| 3061 | | { |
| 3062 | | m_ival = x; |
| 3063 | | } |
| 3064 | | |
| 3065 | | void uniform::set(matrix *mat) |
| 3066 | | { |
| 3067 | | m_mval = mat; |
| 3068 | | } |
| 3069 | | |
| 3070 | | void uniform::set(texture *tex) |
| 3071 | | { |
| 3072 | | m_texture = tex; |
| 3073 | | } |
| 3074 | | |
| 3075 | | void uniform::upload() |
| 3076 | | { |
| 3077 | | switch (m_type) |
| 3078 | | { |
| 3079 | | case UT_INT: |
| 3080 | | m_shader->set_int(m_handle, m_ival); |
| 3081 | | break; |
| 3082 | | case UT_FLOAT: |
| 3083 | | m_shader->set_float(m_handle, m_vec[0]); |
| 3084 | | break; |
| 3085 | | case UT_VEC2: |
| 3086 | | case UT_VEC3: |
| 3087 | | case UT_VEC4: |
| 3088 | | m_shader->set_vector(m_handle, m_count, m_vec); |
| 3089 | | break; |
| 3090 | | case UT_MATRIX: |
| 3091 | | m_shader->set_matrix(m_handle, m_mval); |
| 3092 | | break; |
| 3093 | | case UT_SAMPLER: |
| 3094 | | m_shader->set_texture(m_handle, m_texture); |
| 3095 | | break; |
| 3096 | | } |
| 3097 | | } |
| 3098 | | |
| 3099 | | |
| 3100 | | //============================================================ |
| 3101 | | // effect functions |
| 3102 | | //============================================================ |
| 3103 | | |
| 3104 | | effect::effect(shaders *shadersys, device *dev, const char *name, const char *path) |
| 3105 | | { |
| 3106 | | IDirect3DDevice9 *device = (IDirect3DDevice9 *)dev; |
| 3107 | | LPD3DXBUFFER buffer_errors = NULL; |
| 3108 | | |
| 3109 | | m_shaders = shadersys; |
| 3110 | | m_uniform_head = NULL; |
| 3111 | | m_uniform_tail = NULL; |
| 3112 | | m_effect = NULL; |
| 3113 | | m_valid = false; |
| 3114 | | |
| 3115 | | char name_cstr[1024]; |
| 3116 | | sprintf(name_cstr, "%s\\%s", path, name); |
| 3117 | | TCHAR *effect_name = tstring_from_utf8(name_cstr); |
| 3118 | | |
| 3119 | | HRESULT hr = (*g_load_effect)(device, effect_name, NULL, NULL, 0, NULL, &m_effect, &buffer_errors); |
| 3120 | | if (FAILED(hr)) |
| 3121 | | { |
| 3122 | | if (buffer_errors != NULL) |
| 3123 | | { |
| 3124 | | LPVOID compile_errors = buffer_errors->GetBufferPointer(); |
| 3125 | | printf("Unable to compile shader: %s\n", (const char*)compile_errors); fflush(stdout); |
| 3126 | | } |
| 3127 | | else |
| 3128 | | { |
| 3129 | | printf("Shader %s is missing, corrupt or cannot be compiled.\n", (const char*)name); fflush(stdout); |
| 3130 | | } |
| 3131 | | } |
| 3132 | | else |
| 3133 | | { |
| 3134 | | m_valid = true; |
| 3135 | | } |
| 3136 | | |
| 3137 | | osd_free(effect_name); |
| 3138 | | } |
| 3139 | | |
| 3140 | | effect::~effect() |
| 3141 | | { |
| 3142 | | m_effect->Release(); |
| 3143 | | m_effect = NULL; |
| 3144 | | uniform *curr = m_uniform_head; |
| 3145 | | while (curr != NULL) |
| 3146 | | { |
| 3147 | | uniform *next = curr->get_next(); |
| 3148 | | delete curr; |
| 3149 | | curr = next; |
| 3150 | | } |
| 3151 | | m_uniform_head = NULL; |
| 3152 | | m_uniform_tail = NULL; |
| 3153 | | } |
| 3154 | | |
| 3155 | | void effect::add_uniform(const char *name, uniform::uniform_type type, int id) |
| 3156 | | { |
| 3157 | | uniform *newuniform = new uniform(this, name, type, id); |
| 3158 | | if (newuniform == NULL) |
| 3159 | | { |
| 3160 | | return; |
| 3161 | | } |
| 3162 | | |
| 3163 | | if (m_uniform_head == NULL) |
| 3164 | | { |
| 3165 | | m_uniform_head = newuniform; |
| 3166 | | } |
| 3167 | | if (m_uniform_tail != NULL) |
| 3168 | | { |
| 3169 | | m_uniform_tail->set_next(newuniform); |
| 3170 | | } |
| 3171 | | m_uniform_tail = newuniform; |
| 3172 | | } |
| 3173 | | |
| 3174 | | void effect::update_uniforms() |
| 3175 | | { |
| 3176 | | uniform *curr = m_uniform_head; |
| 3177 | | while(curr != NULL) |
| 3178 | | { |
| 3179 | | curr->update(); |
| 3180 | | curr = curr->get_next(); |
| 3181 | | } |
| 3182 | | } |
| 3183 | | |
| 3184 | | void effect::begin(UINT *passes, DWORD flags) |
| 3185 | | { |
| 3186 | | m_effect->Begin(passes, flags); |
| 3187 | | } |
| 3188 | | |
| 3189 | | void effect::end() |
| 3190 | | { |
| 3191 | | m_effect->End(); |
| 3192 | | } |
| 3193 | | |
| 3194 | | void effect::begin_pass(UINT pass) |
| 3195 | | { |
| 3196 | | m_effect->BeginPass(pass); |
| 3197 | | } |
| 3198 | | |
| 3199 | | void effect::end_pass() |
| 3200 | | { |
| 3201 | | m_effect->EndPass(); |
| 3202 | | } |
| 3203 | | |
| 3204 | | void effect::set_technique(const char *name) |
| 3205 | | { |
| 3206 | | m_effect->SetTechnique(name); |
| 3207 | | } |
| 3208 | | |
| 3209 | | void effect::set_vector(D3DXHANDLE param, int count, float *vector) |
| 3210 | | { |
| 3211 | | static D3DXVECTOR4 out_vector; |
| 3212 | | if (count > 0) |
| 3213 | | { |
| 3214 | | out_vector.x = vector[0]; |
| 3215 | | } |
| 3216 | | if (count > 1) |
| 3217 | | { |
| 3218 | | out_vector.y = vector[1]; |
| 3219 | | } |
| 3220 | | if (count > 2) |
| 3221 | | { |
| 3222 | | out_vector.z = vector[2]; |
| 3223 | | } |
| 3224 | | if (count > 3) |
| 3225 | | { |
| 3226 | | out_vector.w = vector[3]; |
| 3227 | | } |
| 3228 | | m_effect->SetVector(param, &out_vector); |
| 3229 | | } |
| 3230 | | |
| 3231 | | void effect::set_float(D3DXHANDLE param, float value) |
| 3232 | | { |
| 3233 | | m_effect->SetFloat(param, value); |
| 3234 | | } |
| 3235 | | |
| 3236 | | void effect::set_int(D3DXHANDLE param, int value) |
| 3237 | | { |
| 3238 | | m_effect->SetInt(param, value); |
| 3239 | | } |
| 3240 | | |
| 3241 | | void effect::set_bool(D3DXHANDLE param, bool value) |
| 3242 | | { |
| 3243 | | m_effect->SetBool(param, value); |
| 3244 | | } |
| 3245 | | |
| 3246 | | void effect::set_matrix(D3DXHANDLE param, matrix *matrix) |
| 3247 | | { |
| 3248 | | m_effect->SetMatrix(param, (D3DXMATRIX*)matrix); |
| 3249 | | } |
| 3250 | | |
| 3251 | | void effect::set_texture(D3DXHANDLE param, texture *tex) |
| 3252 | | { |
| 3253 | | m_effect->SetTexture(param, (IDirect3DTexture9*)tex); |
| 3254 | | } |
| 3255 | | |
| 3256 | | D3DXHANDLE effect::get_parameter(D3DXHANDLE param, const char *name) |
| 3257 | | { |
| 3258 | | return m_effect->GetParameterByName(param, name); |
| 3259 | | } |
| 3260 | | |
| 3261 | | ULONG effect::release() |
| 3262 | | { |
| 3263 | | return m_effect->Release(); |
| 3264 | | } |
| 3265 | | |
| 3266 | | } |
| 3267 | | |
| 3268 | | |
| 3269 | | //============================================================ |
| 3270 | | // get_slider_list |
| 3271 | | //============================================================ |
| 3272 | | |
| 3273 | | void *windows_osd_interface::get_slider_list() |
| 3274 | | { |
| 3275 | | return (void*)g_slider_list; |
| 3276 | | } |
| 3277 | | |
| 3278 | | |
| 3279 | | // NOTE: The function below is taken directly from src/emu/video.c and should likely be moved into a global helper function. |
| 3280 | | //------------------------------------------------- |
| 3281 | | // open_next - open the next non-existing file of |
| 3282 | | // type filetype according to our numbering |
| 3283 | | // scheme |
| 3284 | | //------------------------------------------------- |
| 3285 | | |
| 3286 | | static file_error open_next(d3d::renderer *d3d, emu_file &file, const char *templ, const char *extension, int idx) |
| 3287 | | { |
| 3288 | | UINT32 origflags = file.openflags(); |
| 3289 | | |
| 3290 | | // handle defaults |
| 3291 | | const char *snapname = templ ? templ : d3d->window().machine().options().snap_name(); |
| 3292 | | |
| 3293 | | if (snapname == NULL || snapname[0] == 0) |
| 3294 | | { |
| 3295 | | snapname = "%g/%i"; |
| 3296 | | } |
| 3297 | | std::string snapstr(snapname); |
| 3298 | | |
| 3299 | | // strip any extension in the provided name |
| 3300 | | int index = snapstr.find_last_of('.'); |
| 3301 | | if (index != -1) |
| 3302 | | { |
| 3303 | | snapstr.substr(0, index); |
| 3304 | | } |
| 3305 | | |
| 3306 | | // handle %d in the template (for image devices) |
| 3307 | | std::string snapdev("%d_"); |
| 3308 | | int pos = snapstr.find(snapdev,0); |
| 3309 | | |
| 3310 | | if (pos != -1) |
| 3311 | | { |
| 3312 | | // if more %d are found, revert to default and ignore them all |
| 3313 | | if (snapstr.find(snapdev, pos + 3) != -1) |
| 3314 | | { |
| 3315 | | snapstr.assign("%g/%i"); |
| 3316 | | } |
| 3317 | | // else if there is a single %d, try to create the correct snapname |
| 3318 | | else |
| 3319 | | { |
| 3320 | | int name_found = 0; |
| 3321 | | |
| 3322 | | // find length of the device name |
| 3323 | | int end1 = snapstr.find("/", pos + 3); |
| 3324 | | int end2 = snapstr.find("%", pos + 3); |
| 3325 | | int end = -1; |
| 3326 | | |
| 3327 | | if ((end1 != -1) && (end2 != -1)) |
| 3328 | | { |
| 3329 | | end = MIN(end1, end2); |
| 3330 | | } |
| 3331 | | else if (end1 != -1) |
| 3332 | | { |
| 3333 | | end = end1; |
| 3334 | | } |
| 3335 | | else if (end2 != -1) |
| 3336 | | { |
| 3337 | | end = end2; |
| 3338 | | } |
| 3339 | | else |
| 3340 | | { |
| 3341 | | end = snapstr.length(); |
| 3342 | | } |
| 3343 | | |
| 3344 | | if (end - pos < 3) |
| 3345 | | { |
| 3346 | | fatalerror("Something very wrong is going on!!!\n"); |
| 3347 | | } |
| 3348 | | |
| 3349 | | // copy the device name to a string |
| 3350 | | std::string snapdevname; |
| 3351 | | snapdevname.assign(snapstr.substr(pos + 3, end - pos - 3)); |
| 3352 | | |
| 3353 | | // verify that there is such a device for this system |
| 3354 | | image_interface_iterator iter(d3d->window().machine().root_device()); |
| 3355 | | for (device_image_interface *image = iter.first(); image != NULL; iter.next()) |
| 3356 | | { |
| 3357 | | // get the device name |
| 3358 | | std::string tempdevname(image->brief_instance_name()); |
| 3359 | | |
| 3360 | | if (snapdevname.compare(tempdevname) == 0) |
| 3361 | | { |
| 3362 | | // verify that such a device has an image mounted |
| 3363 | | if (image->basename() != NULL) |
| 3364 | | { |
| 3365 | | std::string filename(image->basename()); |
| 3366 | | |
| 3367 | | // strip extension |
| 3368 | | filename.substr(0, filename.find_last_of('.')); |
| 3369 | | |
| 3370 | | // setup snapname and remove the %d_ |
| 3371 | | strreplace(snapstr, snapdevname.c_str(), filename.c_str()); |
| 3372 | | snapstr.erase(pos, 3); |
| 3373 | | |
| 3374 | | name_found = 1; |
| 3375 | | } |
| 3376 | | } |
| 3377 | | } |
| 3378 | | |
| 3379 | | // or fallback to default |
| 3380 | | if (name_found == 0) |
| 3381 | | { |
| 3382 | | snapstr.assign("%g/%i"); |
| 3383 | | } |
| 3384 | | } |
| 3385 | | } |
| 3386 | | |
| 3387 | | // add our own index |
| 3388 | | // add our own extension |
| 3389 | | snapstr.append(".").append(extension); |
| 3390 | | |
| 3391 | | // substitute path and gamename up front |
| 3392 | | strreplace(snapstr, "/", PATH_SEPARATOR); |
| 3393 | | strreplace(snapstr, "%g", d3d->window().machine().basename()); |
| 3394 | | |
| 3395 | | // determine if the template has an index; if not, we always use the same name |
| 3396 | | std::string fname; |
| 3397 | | if (snapstr.find("%i") == -1) |
| 3398 | | { |
| 3399 | | fname.assign(snapstr); |
| 3400 | | } |
| 3401 | | |
| 3402 | | // otherwise, we scan for the next available filename |
| 3403 | | else |
| 3404 | | { |
| 3405 | | // try until we succeed |
| 3406 | | std::string seqtext; |
| 3407 | | file.set_openflags(OPEN_FLAG_READ); |
| 3408 | | for (int seq = 0; ; seq++) |
| 3409 | | { |
| 3410 | | // build up the filename |
| 3411 | | strprintf(seqtext, "%04d_%d", seq, idx); |
| 3412 | | strreplace(fname.assign(snapstr), "%i", seqtext.c_str()); |
| 3413 | | |
| 3414 | | // try to open the file; stop when we fail |
| 3415 | | file_error filerr = file.open(fname.c_str()); |
| 3416 | | if (filerr != FILERR_NONE) |
| 3417 | | { |
| 3418 | | break; |
| 3419 | | } |
| 3420 | | } |
| 3421 | | } |
| 3422 | | |
| 3423 | | // create the final file |
| 3424 | | file.set_openflags(origflags); |
| 3425 | | return file.open(fname.c_str()); |
| 3426 | | } |
trunk/src/osd/modules/render/d3d/d3dhlsl.cpp
| r0 | r250288 | |
| 1 | // license:BSD-3-Clause |
| 2 | // copyright-holders:Aaron Giles |
| 3 | //============================================================ |
| 4 | // |
| 5 | // d3dhlsl.c - Win32 Direct3D HLSL implementation |
| 6 | // |
| 7 | //============================================================ |
| 8 | |
| 9 | // Useful info: |
| 10 | // Windows XP/2003 shipped with DirectX 8.1 |
| 11 | // Windows 2000 shipped with DirectX 7a |
| 12 | // Windows 98SE shipped with DirectX 6.1a |
| 13 | // Windows 98 shipped with DirectX 5 |
| 14 | // Windows NT shipped with DirectX 3.0a |
| 15 | // Windows 95 shipped with DirectX 2 |
| 16 | |
| 17 | // standard windows headers |
| 18 | #define WIN32_LEAN_AND_MEAN |
| 19 | #include <windows.h> |
| 20 | #include <tchar.h> |
| 21 | #include <mmsystem.h> |
| 22 | #include <d3d9.h> |
| 23 | #include <d3dx9.h> |
| 24 | #include <math.h> |
| 25 | #undef interface |
| 26 | |
| 27 | // MAME headers |
| 28 | #include "emu.h" |
| 29 | #include "render.h" |
| 30 | #include "ui/ui.h" |
| 31 | #include "rendutil.h" |
| 32 | #include "options.h" |
| 33 | #include "emuopts.h" |
| 34 | #include "aviio.h" |
| 35 | #include "png.h" |
| 36 | #include "screen.h" |
| 37 | |
| 38 | // MAMEOS headers |
| 39 | #include "d3dintf.h" |
| 40 | #include "winmain.h" |
| 41 | #include "window.h" |
| 42 | #include "config.h" |
| 43 | #include "d3dcomm.h" |
| 44 | #include "modules/render/drawd3d.h" |
| 45 | #include "strconv.h" |
| 46 | |
| 47 | |
| 48 | //============================================================ |
| 49 | // GLOBALS |
| 50 | //============================================================ |
| 51 | |
| 52 | static slider_state *g_slider_list; |
| 53 | static file_error open_next(d3d::renderer *d3d, emu_file &file, const char *templ, const char *extension, int idx); |
| 54 | |
| 55 | namespace d3d |
| 56 | { |
| 57 | |
| 58 | //============================================================ |
| 59 | // PROTOTYPES |
| 60 | //============================================================ |
| 61 | |
| 62 | static void get_vector(const char *data, int count, float *out, bool report_error); |
| 63 | |
| 64 | |
| 65 | //============================================================ |
| 66 | // TYPE DEFINITIONS |
| 67 | //============================================================ |
| 68 | |
| 69 | typedef HRESULT (WINAPI *direct3dx9_loadeffect_ptr)(LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, const D3DXMACRO *pDefines, LPD3DXINCLUDE pInclude, DWORD Flags, LPD3DXEFFECTPOOL pPool, LPD3DXEFFECT *ppEffect, LPD3DXBUFFER *ppCompilationErrors); |
| 70 | static direct3dx9_loadeffect_ptr g_load_effect = NULL; |
| 71 | |
| 72 | |
| 73 | //============================================================ |
| 74 | // shader manager constructor |
| 75 | //============================================================ |
| 76 | |
| 77 | shaders::shaders() |
| 78 | { |
| 79 | master_enable = false; |
| 80 | vector_enable = true; |
| 81 | hlsl_prescale_x = 1; |
| 82 | hlsl_prescale_x = 1; |
| 83 | preset = -1; |
| 84 | shadow_texture = NULL; |
| 85 | options = NULL; |
| 86 | paused = true; |
| 87 | lastidx = -1; |
| 88 | targethead = NULL; |
| 89 | cachehead = NULL; |
| 90 | initialized = false; |
| 91 | } |
| 92 | |
| 93 | |
| 94 | //============================================================ |
| 95 | // shaders destructor |
| 96 | //============================================================ |
| 97 | |
| 98 | shaders::~shaders() |
| 99 | { |
| 100 | cache_target *currcache = cachehead; |
| 101 | while(cachehead != NULL) |
| 102 | { |
| 103 | cachehead = currcache->next; |
| 104 | global_free(currcache); |
| 105 | currcache = cachehead; |
| 106 | } |
| 107 | |
| 108 | render_target *currtarget = targethead; |
| 109 | while(targethead != NULL) |
| 110 | { |
| 111 | targethead = currtarget->next; |
| 112 | global_free(currtarget); |
| 113 | currtarget = targethead; |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | |
| 118 | //============================================================ |
| 119 | // shaders::window_save |
| 120 | //============================================================ |
| 121 | |
| 122 | void shaders::window_save() |
| 123 | { |
| 124 | if (!master_enable || !d3dintf->post_fx_available) |
| 125 | { |
| 126 | return; |
| 127 | } |
| 128 | |
| 129 | HRESULT result = (*d3dintf->device.create_texture)(d3d->get_device(), snap_width, snap_height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &snap_copy_texture); |
| 130 | if (result != D3D_OK) |
| 131 | { |
| 132 | osd_printf_verbose("Direct3D: Unable to init system-memory target for HLSL snapshot (%08x), bailing\n", (UINT32)result); |
| 133 | return; |
| 134 | } |
| 135 | (*d3dintf->texture.get_surface_level)(snap_copy_texture, 0, &snap_copy_target); |
| 136 | |
| 137 | result = (*d3dintf->device.create_texture)(d3d->get_device(), snap_width, snap_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &snap_texture); |
| 138 | if (result != D3D_OK) |
| 139 | { |
| 140 | osd_printf_verbose("Direct3D: Unable to init video-memory target for HLSL snapshot (%08x), bailing\n", (UINT32)result); |
| 141 | return; |
| 142 | } |
| 143 | (*d3dintf->texture.get_surface_level)(snap_texture, 0, &snap_target); |
| 144 | |
| 145 | render_snap = true; |
| 146 | snap_rendered = false; |
| 147 | } |
| 148 | |
| 149 | |
| 150 | //============================================================ |
| 151 | // shaders::window_record |
| 152 | //============================================================ |
| 153 | |
| 154 | void shaders::window_record() |
| 155 | { |
| 156 | if (!master_enable || !d3dintf->post_fx_available) |
| 157 | { |
| 158 | return; |
| 159 | } |
| 160 | |
| 161 | windows_options &options = downcast<windows_options &>(machine->options()); |
| 162 | const char *filename = options.d3d_hlsl_write(); |
| 163 | |
| 164 | if (avi_output_file != NULL) |
| 165 | { |
| 166 | end_avi_recording(); |
| 167 | } |
| 168 | else if (filename[0] != 0) |
| 169 | { |
| 170 | begin_avi_recording(filename); |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | |
| 175 | //============================================================ |
| 176 | // shaders::avi_update_snap |
| 177 | //============================================================ |
| 178 | |
| 179 | void shaders::avi_update_snap(surface *surface) |
| 180 | { |
| 181 | if (!master_enable || !d3dintf->post_fx_available) |
| 182 | { |
| 183 | return; |
| 184 | } |
| 185 | |
| 186 | D3DLOCKED_RECT rect; |
| 187 | |
| 188 | // if we don't have a bitmap, or if it's not the right size, allocate a new one |
| 189 | if (!avi_snap.valid() || (int)snap_width != avi_snap.width() || (int)snap_height != avi_snap.height()) |
| 190 | { |
| 191 | avi_snap.allocate((int)snap_width, (int)snap_height); |
| 192 | } |
| 193 | |
| 194 | // copy the texture |
| 195 | HRESULT result = (*d3dintf->device.get_render_target_data)(d3d->get_device(), surface, avi_copy_surface); |
| 196 | if (result != D3D_OK) |
| 197 | { |
| 198 | return; |
| 199 | } |
| 200 | |
| 201 | // lock the texture |
| 202 | result = (*d3dintf->surface.lock_rect)(avi_copy_surface, &rect, NULL, D3DLOCK_DISCARD); |
| 203 | if (result != D3D_OK) |
| 204 | { |
| 205 | return; |
| 206 | } |
| 207 | |
| 208 | // loop over Y |
| 209 | for (int srcy = 0; srcy < (int)snap_height; srcy++) |
| 210 | { |
| 211 | DWORD *src = (DWORD *)((BYTE *)rect.pBits + srcy * rect.Pitch); |
| 212 | UINT32 *dst = &avi_snap.pix32(srcy); |
| 213 | |
| 214 | for (int x = 0; x < snap_width; x++) |
| 215 | { |
| 216 | *dst++ = *src++; |
| 217 | } |
| 218 | } |
| 219 | |
| 220 | // unlock |
| 221 | result = (*d3dintf->surface.unlock_rect)(avi_copy_surface); |
| 222 | if (result != D3D_OK) |
| 223 | { |
| 224 | osd_printf_verbose("Direct3D: Error %08X during texture unlock_rect call\n", (int)result); |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | |
| 229 | |
| 230 | //============================================================ |
| 231 | // hlsl_render_snapshot |
| 232 | //============================================================ |
| 233 | |
| 234 | void shaders::render_snapshot(surface *surface) |
| 235 | { |
| 236 | if (!master_enable || !d3dintf->post_fx_available) |
| 237 | { |
| 238 | return; |
| 239 | } |
| 240 | |
| 241 | D3DLOCKED_RECT rect; |
| 242 | |
| 243 | render_snap = false; |
| 244 | |
| 245 | // if we don't have a bitmap, or if it's not the right size, allocate a new one |
| 246 | if (!avi_snap.valid() || snap_width != (avi_snap.width() / 2) || snap_height != (avi_snap.height() / 2)) |
| 247 | { |
| 248 | avi_snap.allocate(snap_width / 2, snap_height / 2); |
| 249 | } |
| 250 | |
| 251 | // copy the texture |
| 252 | HRESULT result = (*d3dintf->device.get_render_target_data)(d3d->get_device(), surface, snap_copy_target); |
| 253 | if (result != D3D_OK) |
| 254 | { |
| 255 | return; |
| 256 | } |
| 257 | |
| 258 | // lock the texture |
| 259 | result = (*d3dintf->surface.lock_rect)(snap_copy_target, &rect, NULL, D3DLOCK_DISCARD); |
| 260 | if (result != D3D_OK) |
| 261 | { |
| 262 | return; |
| 263 | } |
| 264 | |
| 265 | for (int cy = 0; cy < 2; cy++) |
| 266 | { |
| 267 | for (int cx = 0; cx < 2; cx++) |
| 268 | { |
| 269 | // loop over Y |
| 270 | for (int srcy = 0; srcy < snap_height / 2; srcy++) |
| 271 | { |
| 272 | int toty = (srcy + cy * (snap_height / 2)); |
| 273 | int totx = cx * (snap_width / 2); |
| 274 | DWORD *src = (DWORD *)((BYTE *)rect.pBits + toty * rect.Pitch + totx * 4); |
| 275 | UINT32 *dst = &avi_snap.pix32(srcy); |
| 276 | |
| 277 | for (int x = 0; x < snap_width / 2; x++) |
| 278 | { |
| 279 | *dst++ = *src++; |
| 280 | } |
| 281 | } |
| 282 | |
| 283 | int idx = cy * 2 + cx; |
| 284 | |
| 285 | emu_file file(machine->options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); |
| 286 | file_error filerr = open_next(d3d, file, NULL, "png", idx); |
| 287 | if (filerr != FILERR_NONE) |
| 288 | { |
| 289 | return; |
| 290 | } |
| 291 | |
| 292 | // add two text entries describing the image |
| 293 | std::string text1 = std::string(emulator_info::get_appname()).append(" ").append(build_version); |
| 294 | std::string text2 = std::string(machine->system().manufacturer).append(" ").append(machine->system().description); |
| 295 | png_info pnginfo = { 0 }; |
| 296 | png_add_text(&pnginfo, "Software", text1.c_str()); |
| 297 | png_add_text(&pnginfo, "System", text2.c_str()); |
| 298 | |
| 299 | // now do the actual work |
| 300 | png_error error = png_write_bitmap(file, &pnginfo, avi_snap, 1 << 24, NULL); |
| 301 | if (error != PNGERR_NONE) |
| 302 | { |
| 303 | osd_printf_error("Error generating PNG for HLSL snapshot: png_error = %d\n", error); |
| 304 | } |
| 305 | |
| 306 | // free any data allocated |
| 307 | png_free(&pnginfo); |
| 308 | } |
| 309 | } |
| 310 | |
| 311 | // unlock |
| 312 | result = (*d3dintf->surface.unlock_rect)(snap_copy_target); |
| 313 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during texture unlock_rect call\n", (int)result); |
| 314 | |
| 315 | if (snap_texture != NULL) |
| 316 | { |
| 317 | (*d3dintf->texture.release)(snap_texture); |
| 318 | snap_texture = NULL; |
| 319 | } |
| 320 | |
| 321 | if (snap_target != NULL) |
| 322 | { |
| 323 | (*d3dintf->surface.release)(snap_target); |
| 324 | snap_target = NULL; |
| 325 | } |
| 326 | |
| 327 | if (snap_copy_texture != NULL) |
| 328 | { |
| 329 | (*d3dintf->texture.release)(snap_copy_texture); |
| 330 | snap_copy_texture = NULL; |
| 331 | } |
| 332 | |
| 333 | if (snap_copy_target != NULL) |
| 334 | { |
| 335 | (*d3dintf->surface.release)(snap_copy_target); |
| 336 | snap_copy_target = NULL; |
| 337 | } |
| 338 | } |
| 339 | |
| 340 | |
| 341 | //============================================================ |
| 342 | // shaders::record_texture |
| 343 | //============================================================ |
| 344 | |
| 345 | void shaders::record_texture() |
| 346 | { |
| 347 | if (!master_enable || !d3dintf->post_fx_available) |
| 348 | { |
| 349 | return; |
| 350 | } |
| 351 | |
| 352 | surface *surface = avi_final_target; |
| 353 | |
| 354 | // ignore if nothing to do |
| 355 | if (avi_output_file == NULL || surface == NULL) |
| 356 | { |
| 357 | return; |
| 358 | } |
| 359 | |
| 360 | // get the current time |
| 361 | attotime curtime = machine->time(); |
| 362 | |
| 363 | avi_update_snap(surface); |
| 364 | |
| 365 | // loop until we hit the right time |
| 366 | while (avi_next_frame_time <= curtime) |
| 367 | { |
| 368 | // handle an AVI recording |
| 369 | // write the next frame |
| 370 | avi_error avierr = avi_append_video_frame(avi_output_file, avi_snap); |
| 371 | if (avierr != AVIERR_NONE) |
| 372 | { |
| 373 | end_avi_recording(); |
| 374 | return; |
| 375 | } |
| 376 | |
| 377 | // advance time |
| 378 | avi_next_frame_time += avi_frame_period; |
| 379 | avi_frame++; |
| 380 | } |
| 381 | } |
| 382 | |
| 383 | |
| 384 | //============================================================ |
| 385 | // shaders::end_hlsl_avi_recording |
| 386 | //============================================================ |
| 387 | |
| 388 | void shaders::end_avi_recording() |
| 389 | { |
| 390 | if (!master_enable || !d3dintf->post_fx_available) |
| 391 | { |
| 392 | return; |
| 393 | } |
| 394 | |
| 395 | if (avi_output_file != NULL) |
| 396 | { |
| 397 | avi_close(avi_output_file); |
| 398 | } |
| 399 | |
| 400 | avi_output_file = NULL; |
| 401 | avi_frame = 0; |
| 402 | } |
| 403 | |
| 404 | |
| 405 | //============================================================ |
| 406 | // shaders::toggle |
| 407 | //============================================================ |
| 408 | |
| 409 | void shaders::toggle() |
| 410 | { |
| 411 | if (master_enable) |
| 412 | { |
| 413 | if (initialized) |
| 414 | { |
| 415 | delete_resources(false); |
| 416 | } |
| 417 | master_enable = !master_enable; |
| 418 | } |
| 419 | else |
| 420 | { |
| 421 | if (!initialized) |
| 422 | { |
| 423 | master_enable = !master_enable; |
| 424 | bool failed = create_resources(false); |
| 425 | if (failed) |
| 426 | { |
| 427 | master_enable = false; |
| 428 | } |
| 429 | } |
| 430 | else |
| 431 | { |
| 432 | master_enable = !master_enable; |
| 433 | } |
| 434 | } |
| 435 | } |
| 436 | |
| 437 | //============================================================ |
| 438 | // shaders::begin_avi_recording |
| 439 | //============================================================ |
| 440 | |
| 441 | void shaders::begin_avi_recording(const char *name) |
| 442 | { |
| 443 | if (!master_enable || !d3dintf->post_fx_available) |
| 444 | { |
| 445 | return; |
| 446 | } |
| 447 | |
| 448 | // stop any existing recording |
| 449 | end_avi_recording(); |
| 450 | |
| 451 | // reset the state |
| 452 | avi_frame = 0; |
| 453 | avi_next_frame_time = machine->time(); |
| 454 | |
| 455 | // build up information about this new movie |
| 456 | avi_movie_info info; |
| 457 | info.video_format = 0; |
| 458 | info.video_timescale = 1000 * ((machine->first_screen() != NULL) ? ATTOSECONDS_TO_HZ(machine->first_screen()->frame_period().m_attoseconds) : screen_device::DEFAULT_FRAME_RATE); |
| 459 | info.video_sampletime = 1000; |
| 460 | info.video_numsamples = 0; |
| 461 | info.video_width = snap_width; |
| 462 | info.video_height = snap_height; |
| 463 | info.video_depth = 24; |
| 464 | |
| 465 | info.audio_format = 0; |
| 466 | info.audio_timescale = machine->sample_rate(); |
| 467 | info.audio_sampletime = 1; |
| 468 | info.audio_numsamples = 0; |
| 469 | info.audio_channels = 2; |
| 470 | info.audio_samplebits = 16; |
| 471 | info.audio_samplerate = machine->sample_rate(); |
| 472 | |
| 473 | // create a new temporary movie file |
| 474 | file_error filerr; |
| 475 | std::string fullpath; |
| 476 | { |
| 477 | emu_file tempfile(machine->options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); |
| 478 | if (name != NULL) |
| 479 | { |
| 480 | filerr = tempfile.open(name); |
| 481 | } |
| 482 | else |
| 483 | { |
| 484 | filerr = open_next(d3d, tempfile, NULL, "avi", 0); |
| 485 | } |
| 486 | |
| 487 | // compute the frame time |
| 488 | { |
| 489 | avi_frame_period = attotime::from_seconds(1000) / info.video_timescale; |
| 490 | } |
| 491 | |
| 492 | // if we succeeded, make a copy of the name and create the real file over top |
| 493 | if (filerr == FILERR_NONE) |
| 494 | { |
| 495 | fullpath = tempfile.fullpath(); |
| 496 | } |
| 497 | } |
| 498 | |
| 499 | if (filerr == FILERR_NONE) |
| 500 | { |
| 501 | // create the file and free the string |
| 502 | avi_error avierr = avi_create(fullpath.c_str(), &info, &avi_output_file); |
| 503 | if (avierr != AVIERR_NONE) |
| 504 | { |
| 505 | osd_printf_error("Error creating AVI: %s\n", avi_error_string(avierr)); |
| 506 | } |
| 507 | } |
| 508 | } |
| 509 | |
| 510 | |
| 511 | //============================================================ |
| 512 | // remove_cache_target - remove an active cache target when |
| 513 | // refcount hits zero |
| 514 | //============================================================ |
| 515 | |
| 516 | void shaders::remove_cache_target(cache_target *cache) |
| 517 | { |
| 518 | if (cache != NULL) |
| 519 | { |
| 520 | if (cache == cachehead) |
| 521 | { |
| 522 | cachehead = cachehead->next; |
| 523 | } |
| 524 | |
| 525 | if (cache->prev != NULL) |
| 526 | { |
| 527 | cache->prev->next = cache->next; |
| 528 | } |
| 529 | |
| 530 | if (cache->next != NULL) |
| 531 | { |
| 532 | cache->next->prev = cache->prev; |
| 533 | } |
| 534 | |
| 535 | global_free(cache); |
| 536 | } |
| 537 | } |
| 538 | |
| 539 | |
| 540 | //============================================================ |
| 541 | // remove_render_target - remove an active target |
| 542 | //============================================================ |
| 543 | |
| 544 | void shaders::remove_render_target(texture_info *texture) |
| 545 | { |
| 546 | remove_render_target(find_render_target(texture)); |
| 547 | } |
| 548 | |
| 549 | void shaders::remove_render_target(int width, int height, UINT32 screen_index, UINT32 page_index) |
| 550 | { |
| 551 | render_target *target = find_render_target(width, height, screen_index, page_index); |
| 552 | if (target != NULL) |
| 553 | { |
| 554 | remove_render_target(target); |
| 555 | } |
| 556 | } |
| 557 | |
| 558 | void shaders::remove_render_target(render_target *rt) |
| 559 | { |
| 560 | if (rt != NULL) |
| 561 | { |
| 562 | if (rt == targethead) |
| 563 | { |
| 564 | targethead = targethead->next; |
| 565 | } |
| 566 | |
| 567 | if (rt->prev != NULL) |
| 568 | { |
| 569 | rt->prev->next = rt->next; |
| 570 | } |
| 571 | |
| 572 | if (rt->next != NULL) |
| 573 | { |
| 574 | rt->next->prev = rt->prev; |
| 575 | } |
| 576 | |
| 577 | cache_target *cache = find_cache_target(rt->screen_index, rt->width, rt->height); |
| 578 | if (cache != NULL) |
| 579 | { |
| 580 | remove_cache_target(cache); |
| 581 | } |
| 582 | |
| 583 | int screen_index = rt->screen_index; |
| 584 | int other_page = 1 - rt->page_index; |
| 585 | int width = rt->width; |
| 586 | int height = rt->height; |
| 587 | |
| 588 | global_free(rt); |
| 589 | |
| 590 | // Remove other double-buffered page (if it exists) |
| 591 | remove_render_target(width, height, screen_index, other_page); |
| 592 | } |
| 593 | } |
| 594 | |
| 595 | |
| 596 | //============================================================ |
| 597 | // shaders::set_texture |
| 598 | //============================================================ |
| 599 | |
| 600 | void shaders::set_texture(texture_info *texture) |
| 601 | { |
| 602 | if (!master_enable || !d3dintf->post_fx_available) |
| 603 | { |
| 604 | return; |
| 605 | } |
| 606 | |
| 607 | if (texture != NULL) |
| 608 | { |
| 609 | paused = texture->paused(); |
| 610 | texture->advance_frame(); |
| 611 | } |
| 612 | |
| 613 | // set initial texture to use |
| 614 | texture_info *default_texture = d3d->get_default_texture(); |
| 615 | default_effect->set_texture("Diffuse", (texture == NULL) ? default_texture->get_finaltex() : texture->get_finaltex()); |
| 616 | if (options->yiq_enable) |
| 617 | { |
| 618 | yiq_encode_effect->set_texture("Diffuse", (texture == NULL) ? default_texture->get_finaltex() : texture->get_finaltex()); |
| 619 | } |
| 620 | else |
| 621 | { |
| 622 | color_effect->set_texture("Diffuse", (texture == NULL) ? default_texture->get_finaltex() : texture->get_finaltex()); |
| 623 | } |
| 624 | } |
| 625 | |
| 626 | |
| 627 | //============================================================ |
| 628 | // shaders::init |
| 629 | //============================================================ |
| 630 | |
| 631 | void shaders::init(base *d3dintf, running_machine *machine, d3d::renderer *renderer) |
| 632 | { |
| 633 | if (!d3dintf->post_fx_available) |
| 634 | { |
| 635 | return; |
| 636 | } |
| 637 | |
| 638 | g_load_effect = (direct3dx9_loadeffect_ptr)GetProcAddress(d3dintf->libhandle, "D3DXCreateEffectFromFileW"); |
| 639 | if (g_load_effect == NULL) |
| 640 | { |
| 641 | printf("Direct3D: Unable to find D3DXCreateEffectFromFileW\n"); |
| 642 | d3dintf->post_fx_available = false; |
| 643 | return; |
| 644 | } |
| 645 | |
| 646 | this->d3dintf = d3dintf; |
| 647 | this->machine = machine; |
| 648 | this->d3d = renderer; |
| 649 | this->options = renderer->get_shaders_options(); |
| 650 | |
| 651 | windows_options &winoptions = downcast<windows_options &>(machine->options()); |
| 652 | |
| 653 | master_enable = winoptions.d3d_hlsl_enable(); |
| 654 | hlsl_prescale_x = winoptions.d3d_hlsl_prescale_x(); |
| 655 | hlsl_prescale_y = winoptions.d3d_hlsl_prescale_y(); |
| 656 | snap_width = winoptions.d3d_snap_width(); |
| 657 | snap_height = winoptions.d3d_snap_height(); |
| 658 | |
| 659 | if (!options->params_init) |
| 660 | { |
| 661 | strncpy(options->shadow_mask_texture, winoptions.screen_shadow_mask_texture(), sizeof(options->shadow_mask_texture)); |
| 662 | options->shadow_mask_alpha = winoptions.screen_shadow_mask_alpha(); |
| 663 | options->shadow_mask_count_x = winoptions.screen_shadow_mask_count_x(); |
| 664 | options->shadow_mask_count_y = winoptions.screen_shadow_mask_count_y(); |
| 665 | options->shadow_mask_u_size = winoptions.screen_shadow_mask_u_size(); |
| 666 | options->shadow_mask_v_size = winoptions.screen_shadow_mask_v_size(); |
| 667 | options->shadow_mask_u_offset = winoptions.screen_shadow_mask_u_offset(); |
| 668 | options->shadow_mask_v_offset = winoptions.screen_shadow_mask_v_offset(); |
| 669 | options->curvature = winoptions.screen_curvature(); |
| 670 | options->round_corner = winoptions.screen_round_corner(); |
| 671 | options->smooth_border = winoptions.screen_smooth_border(); |
| 672 | options->reflection = winoptions.screen_reflection(); |
| 673 | options->vignetting = winoptions.screen_vignetting(); |
| 674 | options->scanline_alpha = winoptions.screen_scanline_amount(); |
| 675 | options->scanline_scale = winoptions.screen_scanline_scale(); |
| 676 | options->scanline_height = winoptions.screen_scanline_height(); |
| 677 | options->scanline_bright_scale = winoptions.screen_scanline_bright_scale(); |
| 678 | options->scanline_bright_offset = winoptions.screen_scanline_bright_offset(); |
| 679 | options->scanline_offset = winoptions.screen_scanline_offset(); |
| 680 | get_vector(winoptions.screen_defocus(), 2, options->defocus, TRUE); |
| 681 | get_vector(winoptions.screen_converge_x(), 3, options->converge_x, TRUE); |
| 682 | get_vector(winoptions.screen_converge_y(), 3, options->converge_y, TRUE); |
| 683 | get_vector(winoptions.screen_radial_converge_x(), 3, options->radial_converge_x, TRUE); |
| 684 | get_vector(winoptions.screen_radial_converge_y(), 3, options->radial_converge_y, TRUE); |
| 685 | get_vector(winoptions.screen_red_ratio(), 3, options->red_ratio, TRUE); |
| 686 | get_vector(winoptions.screen_grn_ratio(), 3, options->grn_ratio, TRUE); |
| 687 | get_vector(winoptions.screen_blu_ratio(), 3, options->blu_ratio, TRUE); |
| 688 | get_vector(winoptions.screen_offset(), 3, options->offset, TRUE); |
| 689 | get_vector(winoptions.screen_scale(), 3, options->scale, TRUE); |
| 690 | get_vector(winoptions.screen_power(), 3, options->power, TRUE); |
| 691 | get_vector(winoptions.screen_floor(), 3, options->floor, TRUE); |
| 692 | get_vector(winoptions.screen_phosphor(), 3, options->phosphor, TRUE); |
| 693 | options->saturation = winoptions.screen_saturation(); |
| 694 | options->yiq_enable = winoptions.screen_yiq_enable(); |
| 695 | options->yiq_cc = winoptions.screen_yiq_cc(); |
| 696 | options->yiq_a = winoptions.screen_yiq_a(); |
| 697 | options->yiq_b = winoptions.screen_yiq_b(); |
| 698 | options->yiq_o = winoptions.screen_yiq_o(); |
| 699 | options->yiq_p = winoptions.screen_yiq_p(); |
| 700 | options->yiq_n = winoptions.screen_yiq_n(); |
| 701 | options->yiq_y = winoptions.screen_yiq_y(); |
| 702 | options->yiq_i = winoptions.screen_yiq_i(); |
| 703 | options->yiq_q = winoptions.screen_yiq_q(); |
| 704 | options->yiq_scan_time = winoptions.screen_yiq_scan_time(); |
| 705 | options->yiq_phase_count = winoptions.screen_yiq_phase_count(); |
| 706 | options->vector_length_scale = winoptions.screen_vector_length_scale(); |
| 707 | options->vector_length_ratio = winoptions.screen_vector_length_ratio(); |
| 708 | options->bloom_scale = winoptions.screen_bloom_scale(); |
| 709 | get_vector(winoptions.screen_bloom_overdrive(), 3, options->bloom_overdrive, TRUE); |
| 710 | options->bloom_level0_weight = winoptions.screen_bloom_lvl0_weight(); |
| 711 | options->bloom_level1_weight = winoptions.screen_bloom_lvl1_weight(); |
| 712 | options->bloom_level2_weight = winoptions.screen_bloom_lvl2_weight(); |
| 713 | options->bloom_level3_weight = winoptions.screen_bloom_lvl3_weight(); |
| 714 | options->bloom_level4_weight = winoptions.screen_bloom_lvl4_weight(); |
| 715 | options->bloom_level5_weight = winoptions.screen_bloom_lvl5_weight(); |
| 716 | options->bloom_level6_weight = winoptions.screen_bloom_lvl6_weight(); |
| 717 | options->bloom_level7_weight = winoptions.screen_bloom_lvl7_weight(); |
| 718 | options->bloom_level8_weight = winoptions.screen_bloom_lvl8_weight(); |
| 719 | options->bloom_level9_weight = winoptions.screen_bloom_lvl9_weight(); |
| 720 | options->bloom_level10_weight = winoptions.screen_bloom_lvl10_weight(); |
| 721 | |
| 722 | options->params_init = true; |
| 723 | } |
| 724 | |
| 725 | options->params_dirty = true; |
| 726 | |
| 727 | g_slider_list = init_slider_list(); |
| 728 | } |
| 729 | |
| 730 | |
| 731 | //============================================================ |
| 732 | // shaders::init_fsfx_quad |
| 733 | //============================================================ |
| 734 | |
| 735 | void shaders::init_fsfx_quad(void *vertbuf) |
| 736 | { |
| 737 | // Called at the start of each frame by the D3D code in order to reserve two triangles |
| 738 | // that are guaranteed to be at a fixed position so as to simply use D3DPT_TRIANGLELIST, 0, 2 |
| 739 | // instead of having to do bookkeeping about a specific screen quad |
| 740 | if (!master_enable || !d3dintf->post_fx_available) |
| 741 | { |
| 742 | return; |
| 743 | } |
| 744 | |
| 745 | // get a pointer to the vertex buffer |
| 746 | fsfx_vertices = (vertex *)vertbuf; |
| 747 | if (fsfx_vertices == NULL) |
| 748 | { |
| 749 | return; |
| 750 | } |
| 751 | |
| 752 | // fill in the vertexes clockwise |
| 753 | fsfx_vertices[0].x = 0.0f; |
| 754 | fsfx_vertices[0].y = 0.0f; |
| 755 | fsfx_vertices[1].x = d3d->get_width(); |
| 756 | fsfx_vertices[1].y = 0.0f; |
| 757 | fsfx_vertices[2].x = 0.0f; |
| 758 | fsfx_vertices[2].y = d3d->get_height(); |
| 759 | fsfx_vertices[3].x = d3d->get_width(); |
| 760 | fsfx_vertices[3].y = 0.0f; |
| 761 | fsfx_vertices[4].x = 0.0f; |
| 762 | fsfx_vertices[4].y = d3d->get_height(); |
| 763 | fsfx_vertices[5].x = d3d->get_width(); |
| 764 | fsfx_vertices[5].y = d3d->get_height(); |
| 765 | |
| 766 | fsfx_vertices[0].u0 = 0.0f; |
| 767 | fsfx_vertices[0].v0 = 0.0f; |
| 768 | |
| 769 | fsfx_vertices[1].u0 = 1.0f; |
| 770 | fsfx_vertices[1].v0 = 0.0f; |
| 771 | |
| 772 | fsfx_vertices[2].u0 = 0.0f; |
| 773 | fsfx_vertices[2].v0 = 1.0f; |
| 774 | |
| 775 | fsfx_vertices[3].u0 = 1.0f; |
| 776 | fsfx_vertices[3].v0 = 0.0f; |
| 777 | |
| 778 | fsfx_vertices[4].u0 = 0.0f; |
| 779 | fsfx_vertices[4].v0 = 1.0f; |
| 780 | |
| 781 | fsfx_vertices[5].u0 = 1.0f; |
| 782 | fsfx_vertices[5].v0 = 1.0f; |
| 783 | |
| 784 | fsfx_vertices[0].u1 = 0.0f; |
| 785 | fsfx_vertices[0].v1 = 0.0f; |
| 786 | fsfx_vertices[1].u1 = 0.0f; |
| 787 | fsfx_vertices[1].v1 = 0.0f; |
| 788 | fsfx_vertices[2].u1 = 0.0f; |
| 789 | fsfx_vertices[2].v1 = 0.0f; |
| 790 | fsfx_vertices[3].u1 = 0.0f; |
| 791 | fsfx_vertices[3].v1 = 0.0f; |
| 792 | fsfx_vertices[4].u1 = 0.0f; |
| 793 | fsfx_vertices[4].v1 = 0.0f; |
| 794 | fsfx_vertices[5].u1 = 0.0f; |
| 795 | fsfx_vertices[5].v1 = 0.0f; |
| 796 | |
| 797 | // set the color, Z parameters to standard values |
| 798 | for (int i = 0; i < 6; i++) |
| 799 | { |
| 800 | fsfx_vertices[i].z = 0.0f; |
| 801 | fsfx_vertices[i].rhw = 1.0f; |
| 802 | fsfx_vertices[i].color = D3DCOLOR_ARGB(255, 255, 255, 255); |
| 803 | } |
| 804 | } |
| 805 | |
| 806 | |
| 807 | //============================================================ |
| 808 | // shaders::create_resources |
| 809 | //============================================================ |
| 810 | |
| 811 | int shaders::create_resources(bool reset) |
| 812 | { |
| 813 | if (!master_enable || !d3dintf->post_fx_available) |
| 814 | { |
| 815 | return 0; |
| 816 | } |
| 817 | |
| 818 | HRESULT result = (*d3dintf->device.get_render_target)(d3d->get_device(), 0, &backbuffer); |
| 819 | if (result != D3D_OK) |
| 820 | { |
| 821 | osd_printf_verbose("Direct3D: Error %08X during device get_render_target call\n", (int)result); |
| 822 | } |
| 823 | |
| 824 | result = (*d3dintf->device.create_texture)(d3d->get_device(), 4, 4, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &black_texture); |
| 825 | if (result != D3D_OK) |
| 826 | { |
| 827 | osd_printf_verbose("Direct3D: Unable to init video-memory target for black texture (%08x)\n", (UINT32)result); |
| 828 | return 1; |
| 829 | } |
| 830 | (*d3dintf->texture.get_surface_level)(black_texture, 0, &black_surface); |
| 831 | result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, black_surface); |
| 832 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); |
| 833 | result = (*d3dintf->device.clear)(d3d->get_device(), 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); |
| 834 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result); |
| 835 | result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, backbuffer); |
| 836 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); |
| 837 | |
| 838 | result = (*d3dintf->device.create_texture)(d3d->get_device(), (int)snap_width, (int)snap_height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &avi_copy_texture); |
| 839 | if (result != D3D_OK) |
| 840 | { |
| 841 | osd_printf_verbose("Direct3D: Unable to init system-memory target for HLSL AVI dumping (%08x)\n", (UINT32)result); |
| 842 | return 1; |
| 843 | } |
| 844 | (*d3dintf->texture.get_surface_level)(avi_copy_texture, 0, &avi_copy_surface); |
| 845 | |
| 846 | result = (*d3dintf->device.create_texture)(d3d->get_device(), (int)snap_width, (int)snap_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &avi_final_texture); |
| 847 | if (result != D3D_OK) |
| 848 | { |
| 849 | osd_printf_verbose("Direct3D: Unable to init video-memory target for HLSL AVI dumping (%08x)\n", (UINT32)result); |
| 850 | return 1; |
| 851 | } |
| 852 | (*d3dintf->texture.get_surface_level)(avi_final_texture, 0, &avi_final_target); |
| 853 | |
| 854 | emu_file file(machine->options().art_path(), OPEN_FLAG_READ); |
| 855 | render_load_png(shadow_bitmap, file, NULL, options->shadow_mask_texture); |
| 856 | |
| 857 | // experimental: if we have a shadow bitmap, create a texture for it |
| 858 | if (shadow_bitmap.valid()) |
| 859 | { |
| 860 | render_texinfo texture; |
| 861 | |
| 862 | // fake in the basic data so it looks like it came from render.c |
| 863 | texture.base = shadow_bitmap.raw_pixptr(0); |
| 864 | texture.rowpixels = shadow_bitmap.rowpixels(); |
| 865 | texture.width = shadow_bitmap.width(); |
| 866 | texture.height = shadow_bitmap.height(); |
| 867 | texture.palette = NULL; |
| 868 | texture.seqid = 0; |
| 869 | |
| 870 | // now create it (no prescale, but wrap) |
| 871 | shadow_texture = new texture_info(d3d->get_texture_manager(), &texture, 1, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32) | PRIMFLAG_TEXWRAP_MASK); |
| 872 | } |
| 873 | |
| 874 | const char *fx_dir = downcast<windows_options &>(machine->options()).screen_post_fx_dir(); |
| 875 | |
| 876 | default_effect = new effect(this, d3d->get_device(), "primary.fx", fx_dir); |
| 877 | post_effect = new effect(this, d3d->get_device(), "post.fx", fx_dir); |
| 878 | distortion_effect = new effect(this, d3d->get_device(), "distortion.fx", fx_dir); |
| 879 | prescale_effect = new effect(this, d3d->get_device(), "prescale.fx", fx_dir); |
| 880 | phosphor_effect = new effect(this, d3d->get_device(), "phosphor.fx", fx_dir); |
| 881 | focus_effect = new effect(this, d3d->get_device(), "focus.fx", fx_dir); |
| 882 | deconverge_effect = new effect(this, d3d->get_device(), "deconverge.fx", fx_dir); |
| 883 | color_effect = new effect(this, d3d->get_device(), "color.fx", fx_dir); |
| 884 | yiq_encode_effect = new effect(this, d3d->get_device(), "yiq_encode.fx", fx_dir); |
| 885 | yiq_decode_effect = new effect(this, d3d->get_device(), "yiq_decode.fx", fx_dir); |
| 886 | bloom_effect = new effect(this, d3d->get_device(), "bloom.fx", fx_dir); |
| 887 | downsample_effect = new effect(this, d3d->get_device(), "downsample.fx", fx_dir); |
| 888 | vector_effect = new effect(this, d3d->get_device(), "vector.fx", fx_dir); |
| 889 | |
| 890 | if (!default_effect->is_valid() || |
| 891 | !post_effect->is_valid() || |
| 892 | !distortion_effect->is_valid() || |
| 893 | !prescale_effect->is_valid() || |
| 894 | !phosphor_effect->is_valid() || |
| 895 | !focus_effect->is_valid() || |
| 896 | !deconverge_effect->is_valid() || |
| 897 | !color_effect->is_valid() || |
| 898 | !yiq_encode_effect->is_valid() || |
| 899 | !yiq_decode_effect->is_valid() || |
| 900 | !bloom_effect->is_valid() || |
| 901 | !downsample_effect->is_valid() || |
| 902 | !vector_effect->is_valid()) |
| 903 | { |
| 904 | return 1; |
| 905 | } |
| 906 | |
| 907 | yiq_encode_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 908 | yiq_encode_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS); |
| 909 | yiq_encode_effect->add_uniform("SourceRect", uniform::UT_VEC2, uniform::CU_SOURCE_RECT); |
| 910 | yiq_encode_effect->add_uniform("CCValue", uniform::UT_FLOAT, uniform::CU_NTSC_CCFREQ); |
| 911 | yiq_encode_effect->add_uniform("AValue", uniform::UT_FLOAT, uniform::CU_NTSC_A); |
| 912 | yiq_encode_effect->add_uniform("BValue", uniform::UT_FLOAT, uniform::CU_NTSC_B); |
| 913 | yiq_encode_effect->add_uniform("PValue", uniform::UT_FLOAT, uniform::CU_NTSC_P); |
| 914 | yiq_encode_effect->add_uniform("NotchHalfWidth", uniform::UT_FLOAT, uniform::CU_NTSC_NOTCH); |
| 915 | yiq_encode_effect->add_uniform("YFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_YFREQ); |
| 916 | yiq_encode_effect->add_uniform("IFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_IFREQ); |
| 917 | yiq_encode_effect->add_uniform("QFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_QFREQ); |
| 918 | yiq_encode_effect->add_uniform("ScanTime", uniform::UT_FLOAT, uniform::CU_NTSC_HTIME); |
| 919 | |
| 920 | yiq_decode_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 921 | yiq_decode_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS); |
| 922 | yiq_decode_effect->add_uniform("SourceRect", uniform::UT_VEC2, uniform::CU_SOURCE_RECT); |
| 923 | yiq_decode_effect->add_uniform("CCValue", uniform::UT_FLOAT, uniform::CU_NTSC_CCFREQ); |
| 924 | yiq_decode_effect->add_uniform("AValue", uniform::UT_FLOAT, uniform::CU_NTSC_A); |
| 925 | yiq_decode_effect->add_uniform("BValue", uniform::UT_FLOAT, uniform::CU_NTSC_B); |
| 926 | yiq_decode_effect->add_uniform("OValue", uniform::UT_FLOAT, uniform::CU_NTSC_O); |
| 927 | yiq_decode_effect->add_uniform("PValue", uniform::UT_FLOAT, uniform::CU_NTSC_P); |
| 928 | yiq_decode_effect->add_uniform("NotchHalfWidth", uniform::UT_FLOAT, uniform::CU_NTSC_NOTCH); |
| 929 | yiq_decode_effect->add_uniform("YFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_YFREQ); |
| 930 | yiq_decode_effect->add_uniform("IFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_IFREQ); |
| 931 | yiq_decode_effect->add_uniform("QFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_QFREQ); |
| 932 | yiq_decode_effect->add_uniform("ScanTime", uniform::UT_FLOAT, uniform::CU_NTSC_HTIME); |
| 933 | |
| 934 | color_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 935 | color_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS); |
| 936 | |
| 937 | color_effect->add_uniform("YIQEnable", uniform::UT_FLOAT, uniform::CU_NTSC_ENABLE); |
| 938 | color_effect->add_uniform("RedRatios", uniform::UT_VEC3, uniform::CU_COLOR_RED_RATIOS); |
| 939 | color_effect->add_uniform("GrnRatios", uniform::UT_VEC3, uniform::CU_COLOR_GRN_RATIOS); |
| 940 | color_effect->add_uniform("BluRatios", uniform::UT_VEC3, uniform::CU_COLOR_BLU_RATIOS); |
| 941 | color_effect->add_uniform("Offset", uniform::UT_VEC3, uniform::CU_COLOR_OFFSET); |
| 942 | color_effect->add_uniform("Scale", uniform::UT_VEC3, uniform::CU_COLOR_SCALE); |
| 943 | color_effect->add_uniform("Saturation", uniform::UT_FLOAT, uniform::CU_COLOR_SATURATION); |
| 944 | |
| 945 | prescale_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 946 | prescale_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS); |
| 947 | |
| 948 | deconverge_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 949 | deconverge_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS); |
| 950 | deconverge_effect->add_uniform("SourceRect", uniform::UT_VEC2, uniform::CU_SOURCE_RECT); |
| 951 | deconverge_effect->add_uniform("ConvergeX", uniform::UT_VEC3, uniform::CU_CONVERGE_LINEAR_X); |
| 952 | deconverge_effect->add_uniform("ConvergeY", uniform::UT_VEC3, uniform::CU_CONVERGE_LINEAR_Y); |
| 953 | deconverge_effect->add_uniform("RadialConvergeX", uniform::UT_VEC3, uniform::CU_CONVERGE_RADIAL_X); |
| 954 | deconverge_effect->add_uniform("RadialConvergeY", uniform::UT_VEC3, uniform::CU_CONVERGE_RADIAL_Y); |
| 955 | |
| 956 | focus_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 957 | focus_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS); |
| 958 | focus_effect->add_uniform("Defocus", uniform::UT_VEC2, uniform::CU_FOCUS_SIZE); |
| 959 | |
| 960 | phosphor_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 961 | phosphor_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS); |
| 962 | phosphor_effect->add_uniform("Phosphor", uniform::UT_VEC3, uniform::CU_PHOSPHOR_LIFE); |
| 963 | |
| 964 | downsample_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 965 | |
| 966 | bloom_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 967 | bloom_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS); |
| 968 | |
| 969 | post_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS); |
| 970 | post_effect->add_uniform("SourceRect", uniform::UT_VEC2, uniform::CU_SOURCE_RECT); // backward compatibility |
| 971 | post_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 972 | post_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS); |
| 973 | post_effect->add_uniform("QuadDims", uniform::UT_VEC2, uniform::CU_QUAD_DIMS); // backward compatibility |
| 974 | |
| 975 | post_effect->add_uniform("VignettingAmount", uniform::UT_FLOAT, uniform::CU_POST_VIGNETTING); // backward compatibility |
| 976 | post_effect->add_uniform("CurvatureAmount", uniform::UT_FLOAT, uniform::CU_POST_CURVATURE); // backward compatibility |
| 977 | post_effect->add_uniform("RoundCornerAmount", uniform::UT_FLOAT, uniform::CU_POST_ROUND_CORNER); // backward compatibility |
| 978 | post_effect->add_uniform("SmoothBorderAmount", uniform::UT_FLOAT, uniform::CU_POST_SMOOTH_BORDER); // backward compatibility |
| 979 | post_effect->add_uniform("ReflectionAmount", uniform::UT_FLOAT, uniform::CU_POST_REFLECTION); // backward compatibility |
| 980 | |
| 981 | post_effect->add_uniform("ShadowAlpha", uniform::UT_FLOAT, uniform::CU_POST_SHADOW_ALPHA); |
| 982 | post_effect->add_uniform("ShadowCount", uniform::UT_VEC2, uniform::CU_POST_SHADOW_COUNT); |
| 983 | post_effect->add_uniform("ShadowUV", uniform::UT_VEC2, uniform::CU_POST_SHADOW_UV); |
| 984 | post_effect->add_uniform("ShadowUVOffset", uniform::UT_VEC2, uniform::CU_POST_SHADOW_UV_OFFSET); |
| 985 | post_effect->add_uniform("ShadowDims", uniform::UT_VEC2, uniform::CU_POST_SHADOW_DIMS); |
| 986 | |
| 987 | post_effect->add_uniform("ScanlineAlpha", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_ALPHA); |
| 988 | post_effect->add_uniform("ScanlineScale", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_SCALE); |
| 989 | post_effect->add_uniform("ScanlineHeight", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_HEIGHT); |
| 990 | post_effect->add_uniform("ScanlineBrightScale", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_BRIGHT_SCALE); |
| 991 | post_effect->add_uniform("ScanlineBrightOffset", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_BRIGHT_OFFSET); |
| 992 | post_effect->add_uniform("Power", uniform::UT_VEC3, uniform::CU_POST_POWER); |
| 993 | post_effect->add_uniform("Floor", uniform::UT_VEC3, uniform::CU_POST_FLOOR); |
| 994 | |
| 995 | distortion_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 996 | distortion_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS); |
| 997 | distortion_effect->add_uniform("QuadDims", uniform::UT_VEC2, uniform::CU_QUAD_DIMS); |
| 998 | |
| 999 | distortion_effect->add_uniform("VignettingAmount", uniform::UT_FLOAT, uniform::CU_POST_VIGNETTING); |
| 1000 | distortion_effect->add_uniform("CurvatureAmount", uniform::UT_FLOAT, uniform::CU_POST_CURVATURE); |
| 1001 | distortion_effect->add_uniform("RoundCornerAmount", uniform::UT_FLOAT, uniform::CU_POST_ROUND_CORNER); |
| 1002 | distortion_effect->add_uniform("SmoothBorderAmount", uniform::UT_FLOAT, uniform::CU_POST_SMOOTH_BORDER); |
| 1003 | distortion_effect->add_uniform("ReflectionAmount", uniform::UT_FLOAT, uniform::CU_POST_REFLECTION); |
| 1004 | |
| 1005 | vector_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 1006 | |
| 1007 | default_effect->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS); |
| 1008 | default_effect->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS); |
| 1009 | |
| 1010 | initialized = true; |
| 1011 | |
| 1012 | return 0; |
| 1013 | } |
| 1014 | |
| 1015 | |
| 1016 | //============================================================ |
| 1017 | // shaders::begin_draw |
| 1018 | //============================================================ |
| 1019 | |
| 1020 | void shaders::begin_draw() |
| 1021 | { |
| 1022 | if (!master_enable || !d3dintf->post_fx_available) |
| 1023 | { |
| 1024 | return; |
| 1025 | } |
| 1026 | |
| 1027 | curr_effect = default_effect; |
| 1028 | |
| 1029 | default_effect->set_technique("TestTechnique"); |
| 1030 | post_effect->set_technique("ScanMaskTechnique"); |
| 1031 | distortion_effect->set_technique("DistortionTechnique"); |
| 1032 | phosphor_effect->set_technique("TestTechnique"); |
| 1033 | focus_effect->set_technique("TestTechnique"); |
| 1034 | deconverge_effect->set_technique("DeconvergeTechnique"); |
| 1035 | color_effect->set_technique("ColorTechnique"); |
| 1036 | yiq_encode_effect->set_technique("EncodeTechnique"); |
| 1037 | yiq_decode_effect->set_technique("DecodeTechnique"); |
| 1038 | |
| 1039 | HRESULT result = (*d3dintf->device.get_render_target)(d3d->get_device(), 0, &backbuffer); |
| 1040 | if (result != D3D_OK) |
| 1041 | { |
| 1042 | osd_printf_verbose("Direct3D: Error %08X during device get_render_target call\n", (int)result); |
| 1043 | } |
| 1044 | } |
| 1045 | |
| 1046 | |
| 1047 | //============================================================ |
| 1048 | // shaders::begin_frame |
| 1049 | //============================================================ |
| 1050 | |
| 1051 | void shaders::begin_frame() |
| 1052 | { |
| 1053 | record_texture(); |
| 1054 | } |
| 1055 | |
| 1056 | |
| 1057 | //============================================================ |
| 1058 | // shaders::blit |
| 1059 | //============================================================ |
| 1060 | |
| 1061 | void shaders::blit( |
| 1062 | surface *dst, |
| 1063 | bool clear_dst, |
| 1064 | D3DPRIMITIVETYPE prim_type, |
| 1065 | UINT32 prim_index, |
| 1066 | UINT32 prim_count) |
| 1067 | { |
| 1068 | HRESULT result; |
| 1069 | |
| 1070 | if (dst != NULL) |
| 1071 | { |
| 1072 | result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, dst); |
| 1073 | if (result != D3D_OK) |
| 1074 | { |
| 1075 | osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); |
| 1076 | } |
| 1077 | |
| 1078 | if (clear_dst) |
| 1079 | { |
| 1080 | result = (*d3dintf->device.clear)(d3d->get_device(), 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(1,0,0,0), 0, 0); |
| 1081 | if (result != D3D_OK) |
| 1082 | { |
| 1083 | osd_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result); |
| 1084 | } |
| 1085 | } |
| 1086 | } |
| 1087 | |
| 1088 | UINT num_passes = 0; |
| 1089 | curr_effect->begin(&num_passes, 0); |
| 1090 | |
| 1091 | for (UINT pass = 0; pass < num_passes; pass++) |
| 1092 | { |
| 1093 | curr_effect->begin_pass(pass); |
| 1094 | |
| 1095 | // add the primitives |
| 1096 | result = (*d3dintf->device.draw_primitive)(d3d->get_device(), prim_type, prim_index, prim_count); |
| 1097 | if (result != D3D_OK) |
| 1098 | { |
| 1099 | osd_printf_verbose("Direct3D: Error %08X during device draw_primitive call\n", (int)result); |
| 1100 | } |
| 1101 | |
| 1102 | curr_effect->end_pass(); |
| 1103 | } |
| 1104 | |
| 1105 | curr_effect->end(); |
| 1106 | } |
| 1107 | |
| 1108 | |
| 1109 | //============================================================ |
| 1110 | // shaders::end_frame |
| 1111 | //============================================================ |
| 1112 | |
| 1113 | void shaders::end_frame() |
| 1114 | { |
| 1115 | if (!master_enable || !d3dintf->post_fx_available) |
| 1116 | { |
| 1117 | return; |
| 1118 | } |
| 1119 | |
| 1120 | if (render_snap && snap_rendered) |
| 1121 | { |
| 1122 | render_snapshot(snap_target); |
| 1123 | } |
| 1124 | |
| 1125 | if (!lines_pending) |
| 1126 | { |
| 1127 | return; |
| 1128 | } |
| 1129 | |
| 1130 | lines_pending = false; |
| 1131 | } |
| 1132 | |
| 1133 | |
| 1134 | //============================================================ |
| 1135 | // shaders::init_effect_info |
| 1136 | //============================================================ |
| 1137 | |
| 1138 | void shaders::init_effect_info(poly_info *poly) |
| 1139 | { |
| 1140 | // nothing to do |
| 1141 | } |
| 1142 | |
| 1143 | |
| 1144 | //============================================================ |
| 1145 | // shaders::find_render_target |
| 1146 | //============================================================ |
| 1147 | |
| 1148 | render_target* shaders::find_render_target(texture_info *info) |
| 1149 | { |
| 1150 | UINT32 screen_index_data = (UINT32)info->get_texinfo().osddata; |
| 1151 | UINT32 screen_index = screen_index_data >> 1; |
| 1152 | UINT32 page_index = screen_index_data & 1; |
| 1153 | |
| 1154 | render_target *curr = targethead; |
| 1155 | while (curr != NULL && ( |
| 1156 | curr->screen_index != screen_index || |
| 1157 | curr->page_index != page_index || |
| 1158 | curr->width != info->get_texinfo().width || |
| 1159 | curr->height != info->get_texinfo().height)) |
| 1160 | { |
| 1161 | curr = curr->next; |
| 1162 | } |
| 1163 | |
| 1164 | return curr; |
| 1165 | } |
| 1166 | |
| 1167 | |
| 1168 | //============================================================ |
| 1169 | // shaders::find_render_target |
| 1170 | //============================================================ |
| 1171 | |
| 1172 | render_target* shaders::find_render_target(int width, int height, UINT32 screen_index, UINT32 page_index) |
| 1173 | { |
| 1174 | render_target *curr = targethead; |
| 1175 | while (curr != NULL && ( |
| 1176 | curr->width != width || |
| 1177 | curr->height != height || |
| 1178 | curr->screen_index != screen_index || |
| 1179 | curr->page_index != page_index)) |
| 1180 | { |
| 1181 | curr = curr->next; |
| 1182 | } |
| 1183 | |
| 1184 | return curr; |
| 1185 | } |
| 1186 | |
| 1187 | |
| 1188 | //============================================================ |
| 1189 | // shaders::find_cache_target |
| 1190 | //============================================================ |
| 1191 | |
| 1192 | cache_target* shaders::find_cache_target(UINT32 screen_index, int width, int height) |
| 1193 | { |
| 1194 | cache_target *curr = cachehead; |
| 1195 | while (curr != NULL && ( |
| 1196 | curr->screen_index != screen_index || |
| 1197 | curr->width != width || |
| 1198 | curr->height != height)) |
| 1199 | { |
| 1200 | curr = curr->next; |
| 1201 | } |
| 1202 | |
| 1203 | return curr; |
| 1204 | } |
| 1205 | |
| 1206 | int shaders::ntsc_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1207 | { |
| 1208 | int next_index = source_index; |
| 1209 | |
| 1210 | if (!options->yiq_enable) |
| 1211 | { |
| 1212 | return next_index; |
| 1213 | } |
| 1214 | |
| 1215 | // Convert our signal into YIQ |
| 1216 | curr_effect = yiq_encode_effect; |
| 1217 | curr_effect->update_uniforms(); |
| 1218 | |
| 1219 | // initial "Diffuse" texture is set in shaders::set_texture() |
| 1220 | |
| 1221 | next_index = rt->next_index(next_index); |
| 1222 | blit(rt->native_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2); |
| 1223 | |
| 1224 | // Convert our signal from YIQ |
| 1225 | curr_effect = yiq_decode_effect; |
| 1226 | curr_effect->update_uniforms(); |
| 1227 | curr_effect->set_texture("Composite", rt->native_texture[next_index]); |
| 1228 | curr_effect->set_texture("Diffuse", curr_texture->get_finaltex()); |
| 1229 | |
| 1230 | next_index = rt->next_index(next_index); |
| 1231 | blit(rt->native_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2); |
| 1232 | |
| 1233 | color_effect->set_texture("Diffuse", rt->native_texture[next_index]); |
| 1234 | |
| 1235 | return next_index; |
| 1236 | } |
| 1237 | |
| 1238 | int shaders::color_convolution_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1239 | { |
| 1240 | int next_index = source_index; |
| 1241 | |
| 1242 | curr_effect = color_effect; |
| 1243 | curr_effect->update_uniforms(); |
| 1244 | |
| 1245 | // initial "Diffuse" texture is set in shaders::set_texture() or the result of shaders::ntsc_pass() |
| 1246 | |
| 1247 | next_index = rt->next_index(next_index); |
| 1248 | blit(rt->native_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2); |
| 1249 | |
| 1250 | return next_index; |
| 1251 | } |
| 1252 | |
| 1253 | int shaders::prescale_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1254 | { |
| 1255 | int next_index = source_index; |
| 1256 | |
| 1257 | curr_effect = prescale_effect; |
| 1258 | curr_effect->update_uniforms(); |
| 1259 | curr_effect->set_texture("Diffuse", rt->native_texture[next_index]); |
| 1260 | |
| 1261 | next_index = rt->next_index(next_index); |
| 1262 | blit(rt->prescale_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2); |
| 1263 | |
| 1264 | return next_index; |
| 1265 | } |
| 1266 | |
| 1267 | int shaders::deconverge_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1268 | { |
| 1269 | int next_index = source_index; |
| 1270 | |
| 1271 | curr_effect = deconverge_effect; |
| 1272 | curr_effect->update_uniforms(); |
| 1273 | curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]); |
| 1274 | |
| 1275 | next_index = rt->next_index(next_index); |
| 1276 | blit(rt->prescale_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2); |
| 1277 | |
| 1278 | return next_index; |
| 1279 | } |
| 1280 | |
| 1281 | int shaders::defocus_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1282 | { |
| 1283 | int next_index = source_index; |
| 1284 | |
| 1285 | float defocus_x = options->defocus[0]; |
| 1286 | float defocus_y = options->defocus[1]; |
| 1287 | |
| 1288 | // skip defocus if no influencing settings |
| 1289 | if (defocus_x == 0.0f && defocus_y == 0.0f) |
| 1290 | { |
| 1291 | return next_index; |
| 1292 | } |
| 1293 | |
| 1294 | curr_effect = focus_effect; |
| 1295 | curr_effect->update_uniforms(); |
| 1296 | curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]); |
| 1297 | |
| 1298 | next_index = rt->next_index(next_index); |
| 1299 | blit(rt->prescale_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2); |
| 1300 | |
| 1301 | return next_index; |
| 1302 | } |
| 1303 | |
| 1304 | int shaders::phosphor_pass(render_target *rt, cache_target *ct, int source_index, poly_info *poly, int vertnum) |
| 1305 | { |
| 1306 | int next_index = source_index; |
| 1307 | |
| 1308 | curr_effect = phosphor_effect; |
| 1309 | curr_effect->update_uniforms(); |
| 1310 | curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]); |
| 1311 | curr_effect->set_texture("LastPass", ct->last_texture); |
| 1312 | curr_effect->set_bool("Passthrough", false); |
| 1313 | |
| 1314 | next_index = rt->next_index(next_index); |
| 1315 | blit(rt->prescale_target[next_index], true, D3DPT_TRIANGLELIST, 0, 2); |
| 1316 | |
| 1317 | // Pass along our phosphor'd screen |
| 1318 | curr_effect->update_uniforms(); |
| 1319 | curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]); |
| 1320 | curr_effect->set_texture("LastPass", rt->prescale_texture[next_index]); |
| 1321 | curr_effect->set_bool("Passthrough", true); |
| 1322 | |
| 1323 | // Avoid changing targets due to page flipping |
| 1324 | blit(ct->last_target, true, D3DPT_TRIANGLELIST, 0, 2); |
| 1325 | |
| 1326 | return next_index; |
| 1327 | } |
| 1328 | |
| 1329 | int shaders::post_pass(render_target *rt, int source_index, poly_info *poly, int vertnum, bool prepare_bloom) |
| 1330 | { |
| 1331 | int next_index = source_index; |
| 1332 | |
| 1333 | texture_info *texture = poly->get_texture(); |
| 1334 | |
| 1335 | bool prepare_vector = |
| 1336 | (machine->first_screen()->screen_type() & SCREEN_TYPE_VECTOR) == SCREEN_TYPE_VECTOR; |
| 1337 | bool prepare_raster = |
| 1338 | (machine->first_screen()->screen_type() & SCREEN_TYPE_RASTER) == SCREEN_TYPE_RASTER; |
| 1339 | bool orientation_swap_xy = |
| 1340 | (d3d->window().machine().system().flags & ORIENTATION_SWAP_XY) == ORIENTATION_SWAP_XY; |
| 1341 | bool rotation_swap_xy = |
| 1342 | (d3d->window().target()->orientation() & ROT90) == ROT90 || |
| 1343 | (d3d->window().target()->orientation() & ROT270) == ROT270; |
| 1344 | int rotation_type = |
| 1345 | (d3d->window().target()->orientation() & ROT90) == ROT90 |
| 1346 | ? 1 |
| 1347 | : (d3d->window().target()->orientation() & ROT180) == ROT180 |
| 1348 | ? 2 |
| 1349 | : (d3d->window().target()->orientation() & ROT270) == ROT270 |
| 1350 | ? 3 |
| 1351 | : 0; |
| 1352 | |
| 1353 | curr_effect = post_effect; |
| 1354 | curr_effect->update_uniforms(); |
| 1355 | curr_effect->set_texture("ShadowTexture", shadow_texture == NULL ? NULL : shadow_texture->get_finaltex()); |
| 1356 | curr_effect->set_texture("DiffuseTexture", rt->prescale_texture[next_index]); |
| 1357 | curr_effect->set_float("ScanlineOffset", texture->get_cur_frame() == 0 ? 0.0f : options->scanline_offset); |
| 1358 | curr_effect->set_bool("OrientationSwapXY", orientation_swap_xy); |
| 1359 | curr_effect->set_bool("RotationSwapXY", rotation_swap_xy); |
| 1360 | curr_effect->set_int("RotationType", rotation_type); // backward compatibility |
| 1361 | curr_effect->set_bool("PrepareBloom", prepare_bloom); |
| 1362 | curr_effect->set_bool("PrepareVector", prepare_vector); |
| 1363 | curr_effect->set_bool("PrepareRaster", prepare_raster); |
| 1364 | |
| 1365 | next_index = rt->next_index(next_index); |
| 1366 | blit(prepare_bloom ? rt->native_target[next_index] : rt->prescale_target[next_index], true, poly->get_type(), vertnum, poly->get_count()); |
| 1367 | |
| 1368 | return next_index; |
| 1369 | } |
| 1370 | |
| 1371 | int shaders::downsample_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1372 | { |
| 1373 | int next_index = source_index; |
| 1374 | |
| 1375 | bool prepare_vector = |
| 1376 | (machine->first_screen()->screen_type() & SCREEN_TYPE_VECTOR) == SCREEN_TYPE_VECTOR; |
| 1377 | float bloom_rescale = options->bloom_scale; |
| 1378 | |
| 1379 | // skip downsample if no influencing settings |
| 1380 | if (bloom_rescale == 0.0f) |
| 1381 | { |
| 1382 | return next_index; |
| 1383 | } |
| 1384 | |
| 1385 | curr_effect = downsample_effect; |
| 1386 | curr_effect->update_uniforms(); |
| 1387 | curr_effect->set_bool("PrepareVector", prepare_vector); |
| 1388 | |
| 1389 | int bloom_index = 0; |
| 1390 | float bloom_size = (d3d->get_width() < d3d->get_height()) ? d3d->get_width() : d3d->get_height(); |
| 1391 | float bloom_width = prepare_vector ? rt->target_width : rt->target_width / hlsl_prescale_x; |
| 1392 | float bloom_height = prepare_vector ? rt->target_height : rt->target_height / hlsl_prescale_y; |
| 1393 | for (; bloom_size >= 2.0f && bloom_index < 11; bloom_size *= 0.5f) |
| 1394 | { |
| 1395 | bloom_dims[bloom_index][0] = (float)(int)bloom_width; |
| 1396 | bloom_dims[bloom_index][1] = (float)(int)bloom_height; |
| 1397 | |
| 1398 | curr_effect->set_vector("TargetDims", 2, bloom_dims[bloom_index]); |
| 1399 | curr_effect->set_texture("DiffuseTexture", |
| 1400 | bloom_index == 0 |
| 1401 | ? rt->native_texture[next_index] |
| 1402 | : rt->bloom_texture[bloom_index - 1]); |
| 1403 | |
| 1404 | blit(rt->bloom_target[bloom_index], true, poly->get_type(), vertnum, poly->get_count()); |
| 1405 | |
| 1406 | bloom_width *= 0.5f; |
| 1407 | bloom_height *= 0.5f; |
| 1408 | |
| 1409 | bloom_index++; |
| 1410 | } |
| 1411 | |
| 1412 | bloom_count = bloom_index; |
| 1413 | |
| 1414 | return next_index; |
| 1415 | } |
| 1416 | |
| 1417 | int shaders::bloom_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1418 | { |
| 1419 | int next_index = source_index; |
| 1420 | |
| 1421 | float bloom_rescale = options->bloom_scale; |
| 1422 | |
| 1423 | // skip bloom if no influencing settings |
| 1424 | if (bloom_rescale == 0.0f) |
| 1425 | { |
| 1426 | return next_index; |
| 1427 | } |
| 1428 | |
| 1429 | curr_effect = bloom_effect; |
| 1430 | curr_effect->update_uniforms(); |
| 1431 | |
| 1432 | float weight0123[4] = { |
| 1433 | options->bloom_level0_weight, |
| 1434 | options->bloom_level1_weight * bloom_rescale, |
| 1435 | options->bloom_level2_weight * bloom_rescale, |
| 1436 | options->bloom_level3_weight * bloom_rescale |
| 1437 | }; |
| 1438 | float weight4567[4] = { |
| 1439 | options->bloom_level4_weight * bloom_rescale, |
| 1440 | options->bloom_level5_weight * bloom_rescale, |
| 1441 | options->bloom_level6_weight * bloom_rescale, |
| 1442 | options->bloom_level7_weight * bloom_rescale |
| 1443 | }; |
| 1444 | float weight89A[3] = { |
| 1445 | options->bloom_level8_weight * bloom_rescale, |
| 1446 | options->bloom_level9_weight * bloom_rescale, |
| 1447 | options->bloom_level10_weight * bloom_rescale |
| 1448 | }; |
| 1449 | curr_effect->set_vector("Level0123Weight", 4, weight0123); |
| 1450 | curr_effect->set_vector("Level4567Weight", 4, weight4567); |
| 1451 | curr_effect->set_vector("Level89AWeight", 3, weight89A); |
| 1452 | curr_effect->set_vector("Level01Size", 4, bloom_dims[0]); |
| 1453 | curr_effect->set_vector("Level23Size", 4, bloom_dims[2]); |
| 1454 | curr_effect->set_vector("Level45Size", 4, bloom_dims[4]); |
| 1455 | curr_effect->set_vector("Level67Size", 4, bloom_dims[6]); |
| 1456 | curr_effect->set_vector("Level89Size", 4, bloom_dims[8]); |
| 1457 | curr_effect->set_vector("LevelASize", 2, bloom_dims[10]); |
| 1458 | |
| 1459 | curr_effect->set_vector("OverdriveWeight", 3, options->bloom_overdrive); |
| 1460 | |
| 1461 | curr_effect->set_texture("DiffuseA", rt->prescale_texture[next_index]); |
| 1462 | |
| 1463 | char name[9] = "Diffuse*"; |
| 1464 | for (int index = 1; index < bloom_count; index++) |
| 1465 | { |
| 1466 | name[7] = 'A' + index; |
| 1467 | curr_effect->set_texture(name, rt->bloom_texture[index - 1]); |
| 1468 | } |
| 1469 | for (int index = bloom_count; index < 11; index++) |
| 1470 | { |
| 1471 | name[7] = 'A' + index; |
| 1472 | curr_effect->set_texture(name, black_texture); |
| 1473 | } |
| 1474 | |
| 1475 | next_index = rt->next_index(next_index); |
| 1476 | blit(rt->prescale_target[next_index], true, poly->get_type(), vertnum, poly->get_count()); |
| 1477 | |
| 1478 | return next_index; |
| 1479 | } |
| 1480 | |
| 1481 | int shaders::distortion_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1482 | { |
| 1483 | int next_index = source_index; |
| 1484 | |
| 1485 | // skip distortion if no influencing settings |
| 1486 | if (options->reflection == 0 && |
| 1487 | options->vignetting == 0 && |
| 1488 | options->curvature == 0 && |
| 1489 | options->round_corner == 0 && |
| 1490 | options->smooth_border == 0) |
| 1491 | { |
| 1492 | return next_index; |
| 1493 | } |
| 1494 | |
| 1495 | int screen_count = d3d->window().target()->current_view()->screens().count(); |
| 1496 | |
| 1497 | // only one screen is supported |
| 1498 | if (screen_count > 1) |
| 1499 | { |
| 1500 | return next_index; |
| 1501 | } |
| 1502 | |
| 1503 | render_bounds bounds = d3d->window().target()->current_view()->bounds(); |
| 1504 | render_bounds screen_bounds = d3d->window().target()->current_view()->screen_bounds(); |
| 1505 | |
| 1506 | // artworks are not supported |
| 1507 | if (bounds.x0 != screen_bounds.x0 || |
| 1508 | bounds.y0 != screen_bounds.y0 || |
| 1509 | bounds.x1 != screen_bounds.x1 || |
| 1510 | bounds.y1 != screen_bounds.y1) |
| 1511 | { |
| 1512 | return next_index; |
| 1513 | } |
| 1514 | |
| 1515 | bool orientation_swap_xy = |
| 1516 | (d3d->window().machine().system().flags & ORIENTATION_SWAP_XY) == ORIENTATION_SWAP_XY; |
| 1517 | bool rotation_swap_xy = |
| 1518 | (d3d->window().target()->orientation() & ROT90) == ROT90 || |
| 1519 | (d3d->window().target()->orientation() & ROT270) == ROT270; |
| 1520 | int rotation_type = |
| 1521 | (d3d->window().target()->orientation() & ROT90) == ROT90 |
| 1522 | ? 1 |
| 1523 | : (d3d->window().target()->orientation() & ROT180) == ROT180 |
| 1524 | ? 2 |
| 1525 | : (d3d->window().target()->orientation() & ROT270) == ROT270 |
| 1526 | ? 3 |
| 1527 | : 0; |
| 1528 | |
| 1529 | curr_effect = distortion_effect; |
| 1530 | curr_effect->update_uniforms(); |
| 1531 | curr_effect->set_texture("DiffuseTexture", rt->prescale_texture[next_index]); |
| 1532 | curr_effect->set_bool("OrientationSwapXY", orientation_swap_xy); |
| 1533 | curr_effect->set_bool("RotationSwapXY", rotation_swap_xy); |
| 1534 | curr_effect->set_int("RotationType", rotation_type); |
| 1535 | |
| 1536 | next_index = rt->next_index(next_index); |
| 1537 | blit(rt->prescale_target[next_index], true, poly->get_type(), vertnum, poly->get_count()); |
| 1538 | |
| 1539 | return next_index; |
| 1540 | } |
| 1541 | |
| 1542 | int shaders::vector_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1543 | { |
| 1544 | int next_index = source_index; |
| 1545 | |
| 1546 | float time_params[2] = { 0.0f, 0.0f }; |
| 1547 | float length_params[3] = { poly->get_line_length(), options->vector_length_scale, options->vector_length_ratio }; |
| 1548 | |
| 1549 | curr_effect = vector_effect; |
| 1550 | curr_effect->update_uniforms(); |
| 1551 | curr_effect->set_vector("TimeParams", 2, time_params); |
| 1552 | curr_effect->set_vector("LengthParams", 3, length_params); |
| 1553 | |
| 1554 | blit(rt->prescale_target[next_index], true, poly->get_type(), vertnum, poly->get_count()); |
| 1555 | |
| 1556 | return next_index; |
| 1557 | } |
| 1558 | |
| 1559 | int shaders::vector_buffer_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1560 | { |
| 1561 | int next_index = source_index; |
| 1562 | |
| 1563 | curr_effect = default_effect; |
| 1564 | curr_effect->update_uniforms(); |
| 1565 | |
| 1566 | curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]); |
| 1567 | curr_effect->set_bool("PostPass", true); |
| 1568 | curr_effect->set_float("Brighten", 1.0f); |
| 1569 | |
| 1570 | next_index = rt->next_index(next_index); |
| 1571 | blit(rt->prescale_target[next_index], true, poly->get_type(), vertnum, poly->get_count()); |
| 1572 | |
| 1573 | return next_index; |
| 1574 | } |
| 1575 | |
| 1576 | int shaders::screen_pass(render_target *rt, int source_index, poly_info *poly, int vertnum) |
| 1577 | { |
| 1578 | int next_index = source_index; |
| 1579 | |
| 1580 | bool prepare_vector = |
| 1581 | (machine->first_screen()->screen_type() & SCREEN_TYPE_VECTOR) == SCREEN_TYPE_VECTOR; |
| 1582 | |
| 1583 | curr_effect = default_effect; |
| 1584 | curr_effect->update_uniforms(); |
| 1585 | |
| 1586 | curr_effect->set_texture("Diffuse", rt->prescale_texture[next_index]); |
| 1587 | curr_effect->set_bool("PostPass", true); |
| 1588 | curr_effect->set_float("Brighten", prepare_vector ? 1.0f : 0.0f); |
| 1589 | |
| 1590 | // we do not clear the backbuffe here because multiple screens might rendered into |
| 1591 | blit(backbuffer, false, poly->get_type(), vertnum, poly->get_count()); |
| 1592 | |
| 1593 | if (avi_output_file != NULL) |
| 1594 | { |
| 1595 | blit(avi_final_target, false, poly->get_type(), vertnum, poly->get_count()); |
| 1596 | } |
| 1597 | |
| 1598 | if (render_snap) |
| 1599 | { |
| 1600 | blit(snap_target, false, poly->get_type(), vertnum, poly->get_count()); |
| 1601 | |
| 1602 | snap_rendered = true; |
| 1603 | } |
| 1604 | |
| 1605 | return next_index; |
| 1606 | } |
| 1607 | |
| 1608 | void shaders::menu_pass(poly_info *poly, int vertnum) |
| 1609 | { |
| 1610 | curr_effect = default_effect; |
| 1611 | curr_effect->update_uniforms(); |
| 1612 | curr_effect->set_bool("PostPass", false); |
| 1613 | curr_effect->set_float("Brighten", 0.0f); |
| 1614 | |
| 1615 | blit(NULL, false, poly->get_type(), vertnum, poly->get_count()); |
| 1616 | } |
| 1617 | |
| 1618 | |
| 1619 | //============================================================ |
| 1620 | // shaders::render_quad |
| 1621 | //============================================================ |
| 1622 | |
| 1623 | void shaders::render_quad(poly_info *poly, int vertnum) |
| 1624 | { |
| 1625 | if (!master_enable || !d3dintf->post_fx_available) |
| 1626 | { |
| 1627 | return; |
| 1628 | } |
| 1629 | |
| 1630 | curr_texture = poly->get_texture(); |
| 1631 | curr_poly = poly; |
| 1632 | |
| 1633 | if (PRIMFLAG_GET_SCREENTEX(d3d->get_last_texture_flags()) && curr_texture != NULL) |
| 1634 | { |
| 1635 | curr_render_target = find_render_target(curr_texture); |
| 1636 | |
| 1637 | render_target *rt = curr_render_target; |
| 1638 | if (rt == NULL) |
| 1639 | { |
| 1640 | return; |
| 1641 | } |
| 1642 | |
| 1643 | cache_target *ct = find_cache_target(rt->screen_index, curr_texture->get_texinfo().width, curr_texture->get_texinfo().height); |
| 1644 | |
| 1645 | int next_index = 0; |
| 1646 | |
| 1647 | next_index = ntsc_pass(rt, next_index, poly, vertnum); |
| 1648 | next_index = color_convolution_pass(rt, next_index, poly, vertnum); |
| 1649 | next_index = prescale_pass(rt, next_index, poly, vertnum); |
| 1650 | next_index = deconverge_pass(rt, next_index, poly, vertnum); |
| 1651 | next_index = defocus_pass(rt, next_index, poly, vertnum); // 1st pass |
| 1652 | next_index = defocus_pass(rt, next_index, poly, vertnum); // 2nd pass |
| 1653 | next_index = phosphor_pass(rt, ct, next_index, poly, vertnum); |
| 1654 | |
| 1655 | // create bloom textures |
| 1656 | int phosphor_index = next_index; |
| 1657 | next_index = post_pass(rt, next_index, poly, vertnum, true); |
| 1658 | next_index = downsample_pass(rt, next_index, poly, vertnum); |
| 1659 | |
| 1660 | // apply bloom textures |
| 1661 | next_index = phosphor_index; |
| 1662 | next_index = post_pass(rt, next_index, poly, vertnum, false); |
| 1663 | next_index = bloom_pass(rt, next_index, poly, vertnum); |
| 1664 | |
| 1665 | next_index = distortion_pass(rt, next_index, poly, vertnum); |
| 1666 | |
| 1667 | // render on screen |
| 1668 | d3d->set_wrap(D3DTADDRESS_MIRROR); |
| 1669 | next_index = screen_pass(rt, next_index, poly, vertnum); |
| 1670 | d3d->set_wrap(PRIMFLAG_GET_TEXWRAP(poly->get_texture()->get_flags()) ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP); |
| 1671 | |
| 1672 | curr_texture->increment_frame_count(); |
| 1673 | curr_texture->mask_frame_count(options->yiq_phase_count); |
| 1674 | |
| 1675 | options->params_dirty = false; |
| 1676 | } |
| 1677 | else if (PRIMFLAG_GET_VECTOR(poly->get_flags()) && vector_enable) |
| 1678 | { |
| 1679 | curr_render_target = find_render_target(d3d->get_width(), d3d->get_height(), 0, 0); |
| 1680 | |
| 1681 | render_target *rt = curr_render_target; |
| 1682 | if (rt == NULL) |
| 1683 | { |
| 1684 | return; |
| 1685 | } |
| 1686 | |
| 1687 | lines_pending = true; |
| 1688 | |
| 1689 | int next_index = 0; |
| 1690 | |
| 1691 | next_index = vector_pass(rt, next_index, poly, vertnum); |
| 1692 | |
| 1693 | HRESULT result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, backbuffer); |
| 1694 | if (result != D3D_OK) |
| 1695 | { |
| 1696 | osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); |
| 1697 | } |
| 1698 | } |
| 1699 | else if (PRIMFLAG_GET_VECTORBUF(poly->get_flags()) && vector_enable) |
| 1700 | { |
| 1701 | curr_render_target = find_render_target(d3d->get_width(), d3d->get_height(), 0, 0); |
| 1702 | |
| 1703 | render_target *rt = curr_render_target; |
| 1704 | if (rt == NULL) |
| 1705 | { |
| 1706 | return; |
| 1707 | } |
| 1708 | |
| 1709 | cache_target *ct = find_cache_target(rt->screen_index, rt->width, rt->height); |
| 1710 | |
| 1711 | int next_index = 0; |
| 1712 | |
| 1713 | next_index = vector_buffer_pass(rt, next_index, poly, vertnum); |
| 1714 | next_index = defocus_pass(rt, next_index, poly, vertnum); |
| 1715 | next_index = phosphor_pass(rt, ct, next_index, poly, vertnum); |
| 1716 | |
| 1717 | // create bloom textures |
| 1718 | int phosphor_index = next_index; |
| 1719 | next_index = post_pass(rt, next_index, poly, vertnum, true); |
| 1720 | next_index = downsample_pass(rt, next_index, poly, vertnum); |
| 1721 | |
| 1722 | // apply bloom textures |
| 1723 | next_index = phosphor_index; |
| 1724 | next_index = post_pass(rt, next_index, poly, vertnum, false); |
| 1725 | next_index = bloom_pass(rt, next_index, poly, vertnum); |
| 1726 | |
| 1727 | next_index = distortion_pass(rt, next_index, poly, vertnum); |
| 1728 | |
| 1729 | // render on screen |
| 1730 | next_index = screen_pass(rt, next_index, poly, vertnum); |
| 1731 | |
| 1732 | HRESULT result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, backbuffer); |
| 1733 | if (result != D3D_OK) |
| 1734 | { |
| 1735 | osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); |
| 1736 | } |
| 1737 | |
| 1738 | lines_pending = false; |
| 1739 | } |
| 1740 | else |
| 1741 | { |
| 1742 | menu_pass(poly, vertnum); |
| 1743 | } |
| 1744 | |
| 1745 | curr_render_target = NULL; |
| 1746 | curr_texture = NULL; |
| 1747 | curr_poly = NULL; |
| 1748 | } |
| 1749 | |
| 1750 | |
| 1751 | //============================================================ |
| 1752 | // shaders::end_draw |
| 1753 | //============================================================ |
| 1754 | |
| 1755 | void shaders::end_draw() |
| 1756 | { |
| 1757 | if (!master_enable || !d3dintf->post_fx_available) |
| 1758 | { |
| 1759 | return; |
| 1760 | } |
| 1761 | |
| 1762 | (*d3dintf->surface.release)(backbuffer); |
| 1763 | } |
| 1764 | |
| 1765 | |
| 1766 | //============================================================ |
| 1767 | // shaders::register_prescaled_texture |
| 1768 | //============================================================ |
| 1769 | |
| 1770 | bool shaders::register_prescaled_texture(texture_info *texture) |
| 1771 | { |
| 1772 | return register_texture(texture); |
| 1773 | } |
| 1774 | |
| 1775 | |
| 1776 | //============================================================ |
| 1777 | // shaders::add_cache_target - register a cache target |
| 1778 | //============================================================ |
| 1779 | bool shaders::add_cache_target(renderer* d3d, texture_info* info, int width, int height, int xprescale, int yprescale, int screen_index) |
| 1780 | { |
| 1781 | cache_target* target = (cache_target*)global_alloc_clear(cache_target); |
| 1782 | |
| 1783 | if (!target->init(d3d, d3dintf, width, height, xprescale, yprescale)) |
| 1784 | { |
| 1785 | global_free(target); |
| 1786 | return false; |
| 1787 | } |
| 1788 | |
| 1789 | if (info != NULL) |
| 1790 | { |
| 1791 | target->width = info->get_texinfo().width; |
| 1792 | target->height = info->get_texinfo().height; |
| 1793 | } |
| 1794 | else |
| 1795 | { |
| 1796 | target->width = d3d->get_width(); |
| 1797 | target->height = d3d->get_height(); |
| 1798 | } |
| 1799 | |
| 1800 | target->next = cachehead; |
| 1801 | target->prev = NULL; |
| 1802 | |
| 1803 | target->screen_index = screen_index; |
| 1804 | |
| 1805 | if (cachehead != NULL) |
| 1806 | { |
| 1807 | cachehead->prev = target; |
| 1808 | } |
| 1809 | cachehead = target; |
| 1810 | |
| 1811 | return true; |
| 1812 | } |
| 1813 | |
| 1814 | render_target* shaders::get_vector_target() |
| 1815 | { |
| 1816 | if (!vector_enable) |
| 1817 | { |
| 1818 | return NULL; |
| 1819 | } |
| 1820 | |
| 1821 | return find_render_target(d3d->get_width(), d3d->get_height(), 0, 0); |
| 1822 | } |
| 1823 | |
| 1824 | void shaders::create_vector_target(render_primitive *prim) |
| 1825 | { |
| 1826 | if (!add_render_target(d3d, NULL, d3d->get_width(), d3d->get_height(), 1, 1)) |
| 1827 | { |
| 1828 | vector_enable = false; |
| 1829 | } |
| 1830 | } |
| 1831 | |
| 1832 | |
| 1833 | //============================================================ |
| 1834 | // shaders::add_render_target - register a render target |
| 1835 | //============================================================ |
| 1836 | |
| 1837 | bool shaders::add_render_target(renderer* d3d, texture_info* info, int width, int height, int xprescale, int yprescale) |
| 1838 | { |
| 1839 | UINT32 screen_index = 0; |
| 1840 | UINT32 page_index = 0; |
| 1841 | if (info != NULL) |
| 1842 | { |
| 1843 | render_target *existing_target = find_render_target(info); |
| 1844 | if (existing_target != NULL) |
| 1845 | { |
| 1846 | remove_render_target(existing_target); |
| 1847 | } |
| 1848 | |
| 1849 | UINT32 screen_index_data = (UINT32)info->get_texinfo().osddata; |
| 1850 | screen_index = screen_index_data >> 1; |
| 1851 | page_index = screen_index_data & 1; |
| 1852 | } |
| 1853 | else |
| 1854 | { |
| 1855 | render_target *existing_target = find_render_target(d3d->get_width(), d3d->get_height(), 0, 0); |
| 1856 | if (existing_target != NULL) |
| 1857 | { |
| 1858 | remove_render_target(existing_target); |
| 1859 | } |
| 1860 | } |
| 1861 | |
| 1862 | render_target* target = (render_target*)global_alloc_clear(render_target); |
| 1863 | |
| 1864 | if (!target->init(d3d, d3dintf, width, height, xprescale, yprescale)) |
| 1865 | { |
| 1866 | global_free(target); |
| 1867 | return false; |
| 1868 | } |
| 1869 | |
| 1870 | if (info != NULL) |
| 1871 | { |
| 1872 | target->width = info->get_texinfo().width; |
| 1873 | target->height = info->get_texinfo().height; |
| 1874 | } |
| 1875 | else |
| 1876 | { |
| 1877 | target->width = d3d->get_width(); |
| 1878 | target->height = d3d->get_height(); |
| 1879 | } |
| 1880 | |
| 1881 | HRESULT result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, target->prescale_target[0]); |
| 1882 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); |
| 1883 | result = (*d3dintf->device.clear)(d3d->get_device(), 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); |
| 1884 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result); |
| 1885 | result = (*d3dintf->device.set_render_target)(d3d->get_device(), 0, backbuffer); |
| 1886 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); |
| 1887 | |
| 1888 | target->screen_index = screen_index; |
| 1889 | target->page_index = page_index; |
| 1890 | |
| 1891 | cache_target* cache = find_cache_target(target->screen_index, target->width, target->height); |
| 1892 | if (cache == NULL) |
| 1893 | { |
| 1894 | if (!add_cache_target(d3d, info, width, height, xprescale, yprescale, target->screen_index)) |
| 1895 | { |
| 1896 | global_free(target); |
| 1897 | return false; |
| 1898 | } |
| 1899 | } |
| 1900 | |
| 1901 | target->next = targethead; |
| 1902 | target->prev = NULL; |
| 1903 | |
| 1904 | if (targethead != NULL) |
| 1905 | { |
| 1906 | targethead->prev = target; |
| 1907 | } |
| 1908 | targethead = target; |
| 1909 | |
| 1910 | return true; |
| 1911 | } |
| 1912 | |
| 1913 | |
| 1914 | //============================================================ |
| 1915 | // shaders::enumerate_screens |
| 1916 | //============================================================ |
| 1917 | void shaders::enumerate_screens() |
| 1918 | { |
| 1919 | screen_device_iterator iter(machine->root_device()); |
| 1920 | num_screens = iter.count(); |
| 1921 | } |
| 1922 | |
| 1923 | |
| 1924 | //============================================================ |
| 1925 | // shaders::register_texture(texture::info) |
| 1926 | //============================================================ |
| 1927 | |
| 1928 | bool shaders::register_texture(texture_info *texture) |
| 1929 | { |
| 1930 | int width = texture->get_width(); |
| 1931 | int height = texture->get_height(); |
| 1932 | int xscale = texture->get_xscale(); |
| 1933 | int yscale = texture->get_yscale(); |
| 1934 | |
| 1935 | if (!master_enable || !d3dintf->post_fx_available) |
| 1936 | { |
| 1937 | return false; |
| 1938 | } |
| 1939 | |
| 1940 | enumerate_screens(); |
| 1941 | |
| 1942 | // Find the nearest prescale factor that is over our screen size |
| 1943 | if (hlsl_prescale_x == 0) |
| 1944 | { |
| 1945 | hlsl_prescale_x = 1; |
| 1946 | while (width * xscale * hlsl_prescale_x <= d3d->get_width()) |
| 1947 | { |
| 1948 | hlsl_prescale_x++; |
| 1949 | } |
| 1950 | hlsl_prescale_x--; |
| 1951 | } |
| 1952 | |
| 1953 | if (hlsl_prescale_y == 0) |
| 1954 | { |
| 1955 | hlsl_prescale_y = 1; |
| 1956 | while (height * yscale * hlsl_prescale_y <= d3d->get_height()) |
| 1957 | { |
| 1958 | hlsl_prescale_y++; |
| 1959 | } |
| 1960 | hlsl_prescale_y--; |
| 1961 | } |
| 1962 | |
| 1963 | hlsl_prescale_x = ((hlsl_prescale_x == 0) ? 1 : hlsl_prescale_x); |
| 1964 | hlsl_prescale_y = ((hlsl_prescale_y == 0) ? 1 : hlsl_prescale_y); |
| 1965 | |
| 1966 | if (!add_render_target(d3d, texture, width, height, xscale * hlsl_prescale_x, yscale * hlsl_prescale_y)) |
| 1967 | { |
| 1968 | return false; |
| 1969 | } |
| 1970 | |
| 1971 | options->params_dirty = true; |
| 1972 | |
| 1973 | return true; |
| 1974 | } |
| 1975 | |
| 1976 | |
| 1977 | //============================================================ |
| 1978 | // shaders::delete_resources |
| 1979 | //============================================================ |
| 1980 | |
| 1981 | void shaders::delete_resources(bool reset) |
| 1982 | { |
| 1983 | if (!master_enable || !d3dintf->post_fx_available) |
| 1984 | { |
| 1985 | return; |
| 1986 | } |
| 1987 | |
| 1988 | initialized = false; |
| 1989 | |
| 1990 | options = NULL; |
| 1991 | |
| 1992 | cache_target *currcache = cachehead; |
| 1993 | while(cachehead != NULL) |
| 1994 | { |
| 1995 | cachehead = currcache->next; |
| 1996 | global_free(currcache); |
| 1997 | currcache = cachehead; |
| 1998 | } |
| 1999 | |
| 2000 | render_target *currtarget = targethead; |
| 2001 | while(targethead != NULL) |
| 2002 | { |
| 2003 | targethead = currtarget->next; |
| 2004 | global_free(currtarget); |
| 2005 | currtarget = targethead; |
| 2006 | } |
| 2007 | |
| 2008 | if (downsample_effect != NULL) |
| 2009 | { |
| 2010 | delete downsample_effect; |
| 2011 | downsample_effect = NULL; |
| 2012 | } |
| 2013 | if (bloom_effect != NULL) |
| 2014 | { |
| 2015 | delete bloom_effect; |
| 2016 | bloom_effect = NULL; |
| 2017 | } |
| 2018 | if (vector_effect != NULL) |
| 2019 | { |
| 2020 | delete vector_effect; |
| 2021 | vector_effect = NULL; |
| 2022 | } |
| 2023 | if (default_effect != NULL) |
| 2024 | { |
| 2025 | delete default_effect; |
| 2026 | default_effect = NULL; |
| 2027 | } |
| 2028 | if (post_effect != NULL) |
| 2029 | { |
| 2030 | delete post_effect; |
| 2031 | post_effect = NULL; |
| 2032 | } |
| 2033 | if (distortion_effect != NULL) |
| 2034 | { |
| 2035 | delete distortion_effect; |
| 2036 | distortion_effect = NULL; |
| 2037 | } |
| 2038 | if (prescale_effect != NULL) |
| 2039 | { |
| 2040 | delete prescale_effect; |
| 2041 | prescale_effect = NULL; |
| 2042 | } |
| 2043 | if (phosphor_effect != NULL) |
| 2044 | { |
| 2045 | delete phosphor_effect; |
| 2046 | phosphor_effect = NULL; |
| 2047 | } |
| 2048 | if (focus_effect != NULL) |
| 2049 | { |
| 2050 | delete focus_effect; |
| 2051 | focus_effect = NULL; |
| 2052 | } |
| 2053 | if (deconverge_effect != NULL) |
| 2054 | { |
| 2055 | delete deconverge_effect; |
| 2056 | deconverge_effect = NULL; |
| 2057 | } |
| 2058 | if (color_effect != NULL) |
| 2059 | { |
| 2060 | delete color_effect; |
| 2061 | color_effect = NULL; |
| 2062 | } |
| 2063 | if (yiq_encode_effect != NULL) |
| 2064 | { |
| 2065 | delete yiq_encode_effect; |
| 2066 | yiq_encode_effect = NULL; |
| 2067 | } |
| 2068 | if (yiq_decode_effect != NULL) |
| 2069 | { |
| 2070 | delete yiq_decode_effect; |
| 2071 | yiq_decode_effect = NULL; |
| 2072 | } |
| 2073 | |
| 2074 | if (backbuffer != NULL) |
| 2075 | { |
| 2076 | (*d3dintf->surface.release)(backbuffer); |
| 2077 | backbuffer = NULL; |
| 2078 | } |
| 2079 | |
| 2080 | if (black_surface != NULL) |
| 2081 | { |
| 2082 | (*d3dintf->surface.release)(black_surface); |
| 2083 | black_surface = NULL; |
| 2084 | } |
| 2085 | if (black_texture != NULL) |
| 2086 | { |
| 2087 | (*d3dintf->texture.release)(black_texture); |
| 2088 | black_texture = NULL; |
| 2089 | } |
| 2090 | |
| 2091 | if (avi_copy_texture != NULL) |
| 2092 | { |
| 2093 | (*d3dintf->texture.release)(avi_copy_texture); |
| 2094 | avi_copy_texture = NULL; |
| 2095 | } |
| 2096 | |
| 2097 | if (avi_copy_surface != NULL) |
| 2098 | { |
| 2099 | (*d3dintf->surface.release)(avi_copy_surface); |
| 2100 | avi_copy_surface = NULL; |
| 2101 | } |
| 2102 | |
| 2103 | if (avi_final_texture != NULL) |
| 2104 | { |
| 2105 | (*d3dintf->texture.release)(avi_final_texture); |
| 2106 | avi_final_texture = NULL; |
| 2107 | } |
| 2108 | |
| 2109 | if (avi_final_target != NULL) |
| 2110 | { |
| 2111 | (*d3dintf->surface.release)(avi_final_target); |
| 2112 | avi_final_target = NULL; |
| 2113 | } |
| 2114 | |
| 2115 | shadow_bitmap.reset(); |
| 2116 | } |
| 2117 | |
| 2118 | |
| 2119 | //============================================================ |
| 2120 | // get_vector |
| 2121 | //============================================================ |
| 2122 | |
| 2123 | static void get_vector(const char *data, int count, float *out, bool report_error) |
| 2124 | { |
| 2125 | if (count > 3 && |
| 2126 | sscanf(data, "%f,%f,%f,%f", &out[0], &out[1], &out[2], &out[3]) < 4 && report_error) |
| 2127 | { |
| 2128 | osd_printf_error("Illegal quad vector value = %s\n", data); |
| 2129 | } |
| 2130 | else if (count > 2 && |
| 2131 | sscanf(data, "%f,%f,%f", &out[0], &out[1], &out[2]) < 3 && report_error) |
| 2132 | { |
| 2133 | osd_printf_error("Illegal triple vector value = %s\n", data); |
| 2134 | } |
| 2135 | else if (count > 1 && |
| 2136 | sscanf(data, "%f,%f", &out[0], &out[1]) < 2 && report_error) |
| 2137 | { |
| 2138 | osd_printf_error("Illegal double vector value = %s\n", data); |
| 2139 | } |
| 2140 | else if (count > 0 && |
| 2141 | sscanf(data, "%f", &out[0]) < 1 && report_error) |
| 2142 | { |
| 2143 | osd_printf_error("Illegal single vector value = %s\n", data); |
| 2144 | } |
| 2145 | } |
| 2146 | |
| 2147 | |
| 2148 | /*------------------------------------------------- |
| 2149 | slider_alloc - allocate a new slider entry |
| 2150 | currently duplicated from ui.c, this could |
| 2151 | be done in a more ideal way. |
| 2152 | -------------------------------------------------*/ |
| 2153 | |
| 2154 | static slider_state *slider_alloc(running_machine &machine, const char *title, INT32 minval, INT32 defval, INT32 maxval, INT32 incval, slider_update update, void *arg) |
| 2155 | { |
| 2156 | int size = sizeof(slider_state) + strlen(title); |
| 2157 | slider_state *state = (slider_state *)auto_alloc_array_clear(machine, UINT8, size); |
| 2158 | |
| 2159 | state->minval = minval; |
| 2160 | state->defval = defval; |
| 2161 | state->maxval = maxval; |
| 2162 | state->incval = incval; |
| 2163 | state->update = update; |
| 2164 | state->arg = arg; |
| 2165 | strcpy(state->description, title); |
| 2166 | |
| 2167 | return state; |
| 2168 | } |
| 2169 | |
| 2170 | |
| 2171 | //============================================================ |
| 2172 | // assorted global slider accessors |
| 2173 | //============================================================ |
| 2174 | |
| 2175 | static INT32 slider_set(float *option, float scale, const char *fmt, std::string *str, INT32 newval) |
| 2176 | { |
| 2177 | if (option != NULL && newval != SLIDER_NOCHANGE) |
| 2178 | { |
| 2179 | *option = (float)newval * scale; |
| 2180 | } |
| 2181 | if (str != NULL) |
| 2182 | { |
| 2183 | strprintf(*str, fmt, *option); |
| 2184 | } |
| 2185 | |
| 2186 | return floor(*option / scale + 0.5f); |
| 2187 | } |
| 2188 | |
| 2189 | static INT32 slider_shadow_mask_alpha(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2190 | { |
| 2191 | return slider_set(&(((hlsl_options*)arg)->shadow_mask_alpha), 0.01f, "%2.2f", str, newval); |
| 2192 | } |
| 2193 | |
| 2194 | static INT32 slider_shadow_mask_x_count(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2195 | { |
| 2196 | hlsl_options *options = (hlsl_options*)arg; |
| 2197 | if (newval != SLIDER_NOCHANGE) |
| 2198 | { |
| 2199 | options->shadow_mask_count_x = newval; |
| 2200 | } |
| 2201 | if (str != NULL) |
| 2202 | { |
| 2203 | strprintf(*str, "%d", options->shadow_mask_count_x); |
| 2204 | } |
| 2205 | options->params_dirty = true; |
| 2206 | |
| 2207 | return options->shadow_mask_count_x; |
| 2208 | } |
| 2209 | |
| 2210 | static INT32 slider_shadow_mask_y_count(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2211 | { |
| 2212 | hlsl_options *options = (hlsl_options*)arg; |
| 2213 | if (newval != SLIDER_NOCHANGE) |
| 2214 | { |
| 2215 | options->shadow_mask_count_y = newval; |
| 2216 | } |
| 2217 | if (str != NULL) |
| 2218 | { |
| 2219 | strprintf(*str, "%d", options->shadow_mask_count_y); |
| 2220 | } |
| 2221 | options->params_dirty = true; |
| 2222 | |
| 2223 | return options->shadow_mask_count_y; |
| 2224 | } |
| 2225 | |
| 2226 | static INT32 slider_shadow_mask_usize(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2227 | { |
| 2228 | ((hlsl_options*)arg)->params_dirty = true; |
| 2229 | return slider_set(&(((hlsl_options*)arg)->shadow_mask_u_size), 1.0f / 32.0f, "%2.5f", str, newval); |
| 2230 | } |
| 2231 | |
| 2232 | static INT32 slider_shadow_mask_vsize(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2233 | { |
| 2234 | ((hlsl_options*)arg)->params_dirty = true; |
| 2235 | return slider_set(&(((hlsl_options*)arg)->shadow_mask_v_size), 1.0f / 32.0f, "%2.5f", str, newval); |
| 2236 | } |
| 2237 | |
| 2238 | static INT32 slider_shadow_mask_uoffset(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2239 | { |
| 2240 | ((hlsl_options*)arg)->params_dirty = true; |
| 2241 | return slider_set(&(((hlsl_options*)arg)->shadow_mask_u_offset), 0.01f, "%2.2f", str, newval); |
| 2242 | } |
| 2243 | |
| 2244 | static INT32 slider_shadow_mask_voffset(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2245 | { |
| 2246 | ((hlsl_options*)arg)->params_dirty = true; |
| 2247 | return slider_set(&(((hlsl_options*)arg)->shadow_mask_v_offset), 0.01f, "%2.2f", str, newval); |
| 2248 | } |
| 2249 | |
| 2250 | static INT32 slider_curvature(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2251 | { |
| 2252 | ((hlsl_options*)arg)->params_dirty = true; |
| 2253 | return slider_set(&(((hlsl_options*)arg)->curvature), 0.01f, "%2.2f", str, newval); |
| 2254 | } |
| 2255 | |
| 2256 | static INT32 slider_round_corner(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2257 | { |
| 2258 | ((hlsl_options*)arg)->params_dirty = true; |
| 2259 | return slider_set(&(((hlsl_options*)arg)->round_corner), 0.01f, "%2.2f", str, newval); |
| 2260 | } |
| 2261 | |
| 2262 | static INT32 slider_smooth_border(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2263 | { |
| 2264 | ((hlsl_options*)arg)->params_dirty = true; |
| 2265 | return slider_set(&(((hlsl_options*)arg)->smooth_border), 0.01f, "%2.2f", str, newval); |
| 2266 | } |
| 2267 | |
| 2268 | static INT32 slider_reflection(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2269 | { |
| 2270 | ((hlsl_options*)arg)->params_dirty = true; |
| 2271 | return slider_set(&(((hlsl_options*)arg)->reflection), 0.01f, "%2.2f", str, newval); |
| 2272 | } |
| 2273 | |
| 2274 | static INT32 slider_vignetting(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2275 | { |
| 2276 | ((hlsl_options*)arg)->params_dirty = true; |
| 2277 | return slider_set(&(((hlsl_options*)arg)->vignetting), 0.01f, "%2.2f", str, newval); |
| 2278 | } |
| 2279 | |
| 2280 | static INT32 slider_scanline_alpha(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2281 | { |
| 2282 | ((hlsl_options*)arg)->params_dirty = true; |
| 2283 | return slider_set(&(((hlsl_options*)arg)->scanline_alpha), 0.01f, "%2.2f", str, newval); |
| 2284 | } |
| 2285 | |
| 2286 | static INT32 slider_scanline_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2287 | { |
| 2288 | ((hlsl_options*)arg)->params_dirty = true; |
| 2289 | return slider_set(&(((hlsl_options*)arg)->scanline_scale), 0.05f, "%2.2f", str, newval); |
| 2290 | } |
| 2291 | |
| 2292 | static INT32 slider_scanline_height(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2293 | { |
| 2294 | ((hlsl_options*)arg)->params_dirty = true; |
| 2295 | return slider_set(&(((hlsl_options*)arg)->scanline_height), 0.05f, "%2.2f", str, newval); |
| 2296 | } |
| 2297 | |
| 2298 | static INT32 slider_scanline_bright_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2299 | { |
| 2300 | ((hlsl_options*)arg)->params_dirty = true; |
| 2301 | return slider_set(&(((hlsl_options*)arg)->scanline_bright_scale), 0.05f, "%2.2f", str, newval); |
| 2302 | } |
| 2303 | |
| 2304 | static INT32 slider_scanline_bright_offset(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2305 | { |
| 2306 | ((hlsl_options*)arg)->params_dirty = true; |
| 2307 | return slider_set(&(((hlsl_options*)arg)->scanline_bright_offset), 0.05f, "%2.2f", str, newval); |
| 2308 | } |
| 2309 | |
| 2310 | static INT32 slider_scanline_offset(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2311 | { |
| 2312 | ((hlsl_options*)arg)->params_dirty = true; |
| 2313 | return slider_set(&(((hlsl_options*)arg)->scanline_offset), 0.05f, "%2.2f", str, newval); |
| 2314 | } |
| 2315 | |
| 2316 | static INT32 slider_defocus_x(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2317 | { |
| 2318 | ((hlsl_options*)arg)->params_dirty = true; |
| 2319 | return slider_set(&(((hlsl_options*)arg)->defocus[0]), 0.5f, "%2.1f", str, newval); |
| 2320 | } |
| 2321 | |
| 2322 | static INT32 slider_defocus_y(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2323 | { |
| 2324 | ((hlsl_options*)arg)->params_dirty = true; |
| 2325 | return slider_set(&(((hlsl_options*)arg)->defocus[1]), 0.5f, "%2.1f", str, newval); |
| 2326 | } |
| 2327 | |
| 2328 | static INT32 slider_red_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2329 | { |
| 2330 | ((hlsl_options*)arg)->params_dirty = true; |
| 2331 | return slider_set(&(((hlsl_options*)arg)->converge_x[0]), 0.1f, "%3.1f", str, newval); |
| 2332 | } |
| 2333 | |
| 2334 | static INT32 slider_red_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2335 | { |
| 2336 | ((hlsl_options*)arg)->params_dirty = true; |
| 2337 | return slider_set(&(((hlsl_options*)arg)->converge_y[0]), 0.1f, "%3.1f", str, newval); |
| 2338 | } |
| 2339 | |
| 2340 | static INT32 slider_green_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2341 | { |
| 2342 | ((hlsl_options*)arg)->params_dirty = true; |
| 2343 | return slider_set(&(((hlsl_options*)arg)->converge_x[1]), 0.1f, "%3.1f", str, newval); |
| 2344 | } |
| 2345 | |
| 2346 | static INT32 slider_green_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2347 | { |
| 2348 | ((hlsl_options*)arg)->params_dirty = true; |
| 2349 | return slider_set(&(((hlsl_options*)arg)->converge_y[1]), 0.1f, "%3.1f", str, newval); |
| 2350 | } |
| 2351 | |
| 2352 | static INT32 slider_blue_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2353 | { |
| 2354 | ((hlsl_options*)arg)->params_dirty = true; |
| 2355 | return slider_set(&(((hlsl_options*)arg)->converge_x[2]), 0.1f, "%3.1f", str, newval); |
| 2356 | } |
| 2357 | |
| 2358 | static INT32 slider_blue_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2359 | { |
| 2360 | ((hlsl_options*)arg)->params_dirty = true; |
| 2361 | return slider_set(&(((hlsl_options*)arg)->converge_y[2]), 0.1f, "%3.1f", str, newval); |
| 2362 | } |
| 2363 | |
| 2364 | static INT32 slider_red_radial_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2365 | { |
| 2366 | ((hlsl_options*)arg)->params_dirty = true; |
| 2367 | return slider_set(&(((hlsl_options*)arg)->radial_converge_x[0]), 0.1f, "%3.1f", str, newval); |
| 2368 | } |
| 2369 | |
| 2370 | static INT32 slider_red_radial_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2371 | { |
| 2372 | ((hlsl_options*)arg)->params_dirty = true; |
| 2373 | return slider_set(&(((hlsl_options*)arg)->radial_converge_y[0]), 0.1f, "%3.1f", str, newval); |
| 2374 | } |
| 2375 | |
| 2376 | static INT32 slider_green_radial_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2377 | { |
| 2378 | ((hlsl_options*)arg)->params_dirty = true; |
| 2379 | return slider_set(&(((hlsl_options*)arg)->radial_converge_x[1]), 0.1f, "%3.1f", str, newval); |
| 2380 | } |
| 2381 | |
| 2382 | static INT32 slider_green_radial_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2383 | { |
| 2384 | ((hlsl_options*)arg)->params_dirty = true; |
| 2385 | return slider_set(&(((hlsl_options*)arg)->radial_converge_y[1]), 0.1f, "%3.1f", str, newval); |
| 2386 | } |
| 2387 | |
| 2388 | static INT32 slider_blue_radial_converge_x(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2389 | { |
| 2390 | ((hlsl_options*)arg)->params_dirty = true; |
| 2391 | return slider_set(&(((hlsl_options*)arg)->radial_converge_x[2]), 0.1f, "%3.1f", str, newval); |
| 2392 | } |
| 2393 | |
| 2394 | static INT32 slider_blue_radial_converge_y(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2395 | { |
| 2396 | ((hlsl_options*)arg)->params_dirty = true; |
| 2397 | return slider_set(&(((hlsl_options*)arg)->radial_converge_y[2]), 0.1f, "%3.1f", str, newval); |
| 2398 | } |
| 2399 | |
| 2400 | static INT32 slider_red_from_r(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2401 | { |
| 2402 | ((hlsl_options*)arg)->params_dirty = true; |
| 2403 | return slider_set(&(((hlsl_options*)arg)->red_ratio[0]), 0.005f, "%2.3f", str, newval); |
| 2404 | } |
| 2405 | |
| 2406 | static INT32 slider_red_from_g(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2407 | { |
| 2408 | ((hlsl_options*)arg)->params_dirty = true; |
| 2409 | return slider_set(&(((hlsl_options*)arg)->red_ratio[1]), 0.005f, "%2.3f", str, newval); |
| 2410 | } |
| 2411 | |
| 2412 | static INT32 slider_red_from_b(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2413 | { |
| 2414 | ((hlsl_options*)arg)->params_dirty = true; |
| 2415 | return slider_set(&(((hlsl_options*)arg)->red_ratio[2]), 0.005f, "%2.3f", str, newval); |
| 2416 | } |
| 2417 | |
| 2418 | static INT32 slider_green_from_r(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2419 | { |
| 2420 | ((hlsl_options*)arg)->params_dirty = true; |
| 2421 | return slider_set(&(((hlsl_options*)arg)->grn_ratio[0]), 0.005f, "%2.3f", str, newval); |
| 2422 | } |
| 2423 | |
| 2424 | static INT32 slider_green_from_g(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2425 | { |
| 2426 | ((hlsl_options*)arg)->params_dirty = true; |
| 2427 | return slider_set(&(((hlsl_options*)arg)->grn_ratio[1]), 0.005f, "%2.3f", str, newval); |
| 2428 | } |
| 2429 | |
| 2430 | static INT32 slider_green_from_b(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2431 | { |
| 2432 | ((hlsl_options*)arg)->params_dirty = true; |
| 2433 | return slider_set(&(((hlsl_options*)arg)->grn_ratio[2]), 0.005f, "%2.3f", str, newval); |
| 2434 | } |
| 2435 | |
| 2436 | static INT32 slider_blue_from_r(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2437 | { |
| 2438 | ((hlsl_options*)arg)->params_dirty = true; |
| 2439 | return slider_set(&(((hlsl_options*)arg)->blu_ratio[0]), 0.005f, "%2.3f", str, newval); |
| 2440 | } |
| 2441 | |
| 2442 | static INT32 slider_blue_from_g(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2443 | { |
| 2444 | ((hlsl_options*)arg)->params_dirty = true; |
| 2445 | return slider_set(&(((hlsl_options*)arg)->blu_ratio[1]), 0.005f, "%2.3f", str, newval); |
| 2446 | } |
| 2447 | |
| 2448 | static INT32 slider_blue_from_b(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2449 | { |
| 2450 | ((hlsl_options*)arg)->params_dirty = true; |
| 2451 | return slider_set(&(((hlsl_options*)arg)->blu_ratio[2]), 0.005f, "%2.3f", str, newval); |
| 2452 | } |
| 2453 | |
| 2454 | static INT32 slider_red_offset(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2455 | { |
| 2456 | ((hlsl_options*)arg)->params_dirty = true; |
| 2457 | return slider_set(&(((hlsl_options*)arg)->offset[0]), 0.01f, "%2.2f", str, newval); |
| 2458 | } |
| 2459 | |
| 2460 | static INT32 slider_green_offset(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2461 | { |
| 2462 | ((hlsl_options*)arg)->params_dirty = true; |
| 2463 | return slider_set(&(((hlsl_options*)arg)->offset[1]), 0.01f, "%2.2f", str, newval); |
| 2464 | } |
| 2465 | |
| 2466 | static INT32 slider_blue_offset(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2467 | { |
| 2468 | ((hlsl_options*)arg)->params_dirty = true; |
| 2469 | return slider_set(&(((hlsl_options*)arg)->offset[2]), 0.01f, "%2.2f", str, newval); |
| 2470 | } |
| 2471 | |
| 2472 | static INT32 slider_red_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2473 | { |
| 2474 | ((hlsl_options*)arg)->params_dirty = true; |
| 2475 | return slider_set(&(((hlsl_options*)arg)->scale[0]), 0.01f, "%2.2f", str, newval); |
| 2476 | } |
| 2477 | |
| 2478 | static INT32 slider_green_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2479 | { |
| 2480 | ((hlsl_options*)arg)->params_dirty = true; |
| 2481 | return slider_set(&(((hlsl_options*)arg)->scale[1]), 0.01f, "%2.2f", str, newval); |
| 2482 | } |
| 2483 | |
| 2484 | static INT32 slider_blue_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2485 | { |
| 2486 | ((hlsl_options*)arg)->params_dirty = true; |
| 2487 | return slider_set(&(((hlsl_options*)arg)->scale[2]), 0.01f, "%2.2f", str, newval); |
| 2488 | } |
| 2489 | |
| 2490 | static INT32 slider_red_power(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2491 | { |
| 2492 | ((hlsl_options*)arg)->params_dirty = true; |
| 2493 | return slider_set(&(((hlsl_options*)arg)->power[0]), 0.05f, "%2.2f", str, newval); |
| 2494 | } |
| 2495 | |
| 2496 | static INT32 slider_green_power(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2497 | { |
| 2498 | ((hlsl_options*)arg)->params_dirty = true; |
| 2499 | return slider_set(&(((hlsl_options*)arg)->power[1]), 0.05f, "%2.2f", str, newval); |
| 2500 | } |
| 2501 | |
| 2502 | static INT32 slider_blue_power(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2503 | { |
| 2504 | ((hlsl_options*)arg)->params_dirty = true; |
| 2505 | return slider_set(&(((hlsl_options*)arg)->power[2]), 0.05f, "%2.2f", str, newval); |
| 2506 | } |
| 2507 | |
| 2508 | static INT32 slider_red_floor(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2509 | { |
| 2510 | ((hlsl_options*)arg)->params_dirty = true; |
| 2511 | return slider_set(&(((hlsl_options*)arg)->floor[0]), 0.01f, "%2.2f", str, newval); |
| 2512 | } |
| 2513 | |
| 2514 | static INT32 slider_green_floor(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2515 | { |
| 2516 | ((hlsl_options*)arg)->params_dirty = true; |
| 2517 | return slider_set(&(((hlsl_options*)arg)->floor[1]), 0.01f, "%2.2f", str, newval); |
| 2518 | } |
| 2519 | |
| 2520 | static INT32 slider_blue_floor(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2521 | { |
| 2522 | ((hlsl_options*)arg)->params_dirty = true; |
| 2523 | return slider_set(&(((hlsl_options*)arg)->floor[2]), 0.01f, "%2.2f", str, newval); |
| 2524 | } |
| 2525 | |
| 2526 | static INT32 slider_red_phosphor_life(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2527 | { |
| 2528 | ((hlsl_options*)arg)->params_dirty = true; |
| 2529 | return slider_set(&(((hlsl_options*)arg)->phosphor[0]), 0.01f, "%2.2f", str, newval); |
| 2530 | } |
| 2531 | |
| 2532 | static INT32 slider_green_phosphor_life(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2533 | { |
| 2534 | ((hlsl_options*)arg)->params_dirty = true; |
| 2535 | return slider_set(&(((hlsl_options*)arg)->phosphor[1]), 0.01f, "%2.2f", str, newval); |
| 2536 | } |
| 2537 | |
| 2538 | static INT32 slider_blue_phosphor_life(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2539 | { |
| 2540 | ((hlsl_options*)arg)->params_dirty = true; |
| 2541 | return slider_set(&(((hlsl_options*)arg)->phosphor[2]), 0.01f, "%2.2f", str, newval); |
| 2542 | } |
| 2543 | |
| 2544 | static INT32 slider_saturation(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2545 | { |
| 2546 | ((hlsl_options*)arg)->params_dirty = true; |
| 2547 | return slider_set(&(((hlsl_options*)arg)->saturation), 0.01f, "%2.2f", str, newval); |
| 2548 | } |
| 2549 | |
| 2550 | static INT32 slider_vector_attenuation(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2551 | { |
| 2552 | ((hlsl_options*)arg)->params_dirty = true; |
| 2553 | return slider_set(&(((hlsl_options*)arg)->vector_length_scale), 0.01f, "%1.2f", str, newval); |
| 2554 | } |
| 2555 | |
| 2556 | static INT32 slider_vector_length_max(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2557 | { |
| 2558 | ((hlsl_options*)arg)->params_dirty = true; |
| 2559 | return slider_set(&(((hlsl_options*)arg)->vector_length_ratio), 1.0f, "%4f", str, newval); |
| 2560 | } |
| 2561 | |
| 2562 | static INT32 slider_bloom_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2563 | { |
| 2564 | ((hlsl_options*)arg)->params_dirty = true; |
| 2565 | return slider_set(&(((hlsl_options*)arg)->bloom_scale), 0.001f, "%1.3f", str, newval); |
| 2566 | } |
| 2567 | |
| 2568 | static INT32 slider_bloom_red_overdrive(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2569 | { |
| 2570 | ((hlsl_options*)arg)->params_dirty = true; |
| 2571 | return slider_set(&(((hlsl_options*)arg)->bloom_overdrive[0]), 0.001f, "%1.3f", str, newval); |
| 2572 | } |
| 2573 | |
| 2574 | static INT32 slider_bloom_green_overdrive(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2575 | { |
| 2576 | ((hlsl_options*)arg)->params_dirty = true; |
| 2577 | return slider_set(&(((hlsl_options*)arg)->bloom_overdrive[1]), 0.001f, "%1.3f", str, newval); |
| 2578 | } |
| 2579 | |
| 2580 | static INT32 slider_bloom_blue_overdrive(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2581 | { |
| 2582 | ((hlsl_options*)arg)->params_dirty = true; |
| 2583 | return slider_set(&(((hlsl_options*)arg)->bloom_overdrive[2]), 0.001f, "%1.3f", str, newval); |
| 2584 | } |
| 2585 | |
| 2586 | static INT32 slider_bloom_lvl0_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2587 | { |
| 2588 | ((hlsl_options*)arg)->params_dirty = true; |
| 2589 | return slider_set(&(((hlsl_options*)arg)->bloom_level0_weight), 0.01f, "%1.2f", str, newval); |
| 2590 | } |
| 2591 | |
| 2592 | static INT32 slider_bloom_lvl1_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2593 | { |
| 2594 | ((hlsl_options*)arg)->params_dirty = true; |
| 2595 | return slider_set(&(((hlsl_options*)arg)->bloom_level1_weight), 0.01f, "%1.2f", str, newval); |
| 2596 | } |
| 2597 | |
| 2598 | static INT32 slider_bloom_lvl2_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2599 | { |
| 2600 | ((hlsl_options*)arg)->params_dirty = true; |
| 2601 | return slider_set(&(((hlsl_options*)arg)->bloom_level2_weight), 0.01f, "%1.2f", str, newval); |
| 2602 | } |
| 2603 | |
| 2604 | static INT32 slider_bloom_lvl3_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2605 | { |
| 2606 | ((hlsl_options*)arg)->params_dirty = true; |
| 2607 | return slider_set(&(((hlsl_options*)arg)->bloom_level3_weight), 0.01f, "%1.2f", str, newval); |
| 2608 | } |
| 2609 | |
| 2610 | static INT32 slider_bloom_lvl4_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2611 | { |
| 2612 | ((hlsl_options*)arg)->params_dirty = true; |
| 2613 | return slider_set(&(((hlsl_options*)arg)->bloom_level4_weight), 0.01f, "%1.2f", str, newval); |
| 2614 | } |
| 2615 | |
| 2616 | static INT32 slider_bloom_lvl5_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2617 | { |
| 2618 | ((hlsl_options*)arg)->params_dirty = true; |
| 2619 | return slider_set(&(((hlsl_options*)arg)->bloom_level5_weight), 0.01f, "%1.2f", str, newval); |
| 2620 | } |
| 2621 | |
| 2622 | static INT32 slider_bloom_lvl6_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2623 | { |
| 2624 | ((hlsl_options*)arg)->params_dirty = true; |
| 2625 | return slider_set(&(((hlsl_options*)arg)->bloom_level6_weight), 0.01f, "%1.2f", str, newval); |
| 2626 | } |
| 2627 | |
| 2628 | static INT32 slider_bloom_lvl7_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2629 | { |
| 2630 | ((hlsl_options*)arg)->params_dirty = true; |
| 2631 | return slider_set(&(((hlsl_options*)arg)->bloom_level7_weight), 0.01f, "%1.2f", str, newval); |
| 2632 | } |
| 2633 | |
| 2634 | static INT32 slider_bloom_lvl8_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2635 | { |
| 2636 | ((hlsl_options*)arg)->params_dirty = true; |
| 2637 | return slider_set(&(((hlsl_options*)arg)->bloom_level8_weight), 0.01f, "%1.2f", str, newval); |
| 2638 | } |
| 2639 | |
| 2640 | static INT32 slider_bloom_lvl9_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2641 | { |
| 2642 | ((hlsl_options*)arg)->params_dirty = true; |
| 2643 | return slider_set(&(((hlsl_options*)arg)->bloom_level9_weight), 0.01f, "%1.2f", str, newval); |
| 2644 | } |
| 2645 | |
| 2646 | static INT32 slider_bloom_lvl10_scale(running_machine &machine, void *arg, std::string *str, INT32 newval) |
| 2647 | { |
| 2648 | ((hlsl_options*)arg)->params_dirty = true; |
| 2649 | return slider_set(&(((hlsl_options*)arg)->bloom_level10_weight), 0.01f, "%1.2f", str, newval); |
| 2650 | } |
| 2651 | |
| 2652 | |
| 2653 | //============================================================ |
| 2654 | // init_slider_list |
| 2655 | //============================================================ |
| 2656 | |
| 2657 | shaders::slider_desc shaders::s_sliders[] = |
| 2658 | { |
| 2659 | { "Vector Length Attenuation", 0, 80, 100, 1, 2, slider_vector_attenuation }, |
| 2660 | { "Vector Attenuation Length Limit", 1, 500, 1000, 1, 2, slider_vector_length_max }, |
| 2661 | { "Shadow Mask Darkness", 0, 0, 100, 1, 7, slider_shadow_mask_alpha }, |
| 2662 | { "Shadow Mask X Count", 1, 6, 1024, 1, 7, slider_shadow_mask_x_count }, |
| 2663 | { "Shadow Mask Y Count", 1, 6, 1024, 1, 7, slider_shadow_mask_y_count }, |
| 2664 | { "Shadow Mask Pixel Count X", 1, 6, 64, 1, 7, slider_shadow_mask_usize }, |
| 2665 | { "Shadow Mask Pixel Count Y", 1, 6, 64, 1, 7, slider_shadow_mask_vsize }, |
| 2666 | { "Shadow Mask Offset X", -100, 0, 100, 1, 7, slider_shadow_mask_uoffset }, |
| 2667 | { "Shadow Mask Offset Y", -100, 0, 100, 1, 7, slider_shadow_mask_voffset }, |
| 2668 | { "Screen Curvature", 0, 0, 100, 1, 7, slider_curvature }, |
| 2669 | { "Screen Round Corner", 0, 0, 100, 1, 7, slider_round_corner }, |
| 2670 | { "Screen Smooth Border", 0, 0, 100, 1, 7, slider_smooth_border }, |
| 2671 | { "Screen Reflection", 0, 0, 100, 1, 7, slider_reflection }, |
| 2672 | { "Image Vignetting", 0, 0, 100, 1, 7, slider_vignetting }, |
| 2673 | { "Scanline Darkness", 0, 100, 100, 1, 1, slider_scanline_alpha }, |
| 2674 | { "Scanline Screen Height", 1, 20, 80, 1, 1, slider_scanline_scale }, |
| 2675 | { "Scanline Indiv. Height", 1, 20, 80, 1, 1, slider_scanline_height }, |
| 2676 | { "Scanline Brightness", 0, 20, 40, 1, 1, slider_scanline_bright_scale }, |
| 2677 | { "Scanline Brightness Overdrive", 0, 0, 20, 1, 1, slider_scanline_bright_offset }, |
| 2678 | { "Scanline Jitter", 0, 0, 40, 1, 1, slider_scanline_offset }, |
| 2679 | { "Defocus X", 0, 0, 64, 1, 3, slider_defocus_x }, |
| 2680 | { "Defocus Y", 0, 0, 64, 1, 3, slider_defocus_y }, |
| 2681 | { "Red Position Offset X", -1500, 3, 1500, 1, 3, slider_red_converge_x }, |
| 2682 | { "Red Position Offset Y", -1500, 0, 1500, 1, 3, slider_red_converge_y }, |
| 2683 | { "Green Position Offset X", -1500, 0, 1500, 1, 3, slider_green_converge_x }, |
| 2684 | { "Green Position Offset Y", -1500, 3, 1500, 1, 3, slider_green_converge_y }, |
| 2685 | { "Blue Position Offset X", -1500, 3, 1500, 1, 3, slider_blue_converge_x }, |
| 2686 | { "Blue Position Offset Y", -1500, 3, 1500, 1, 3, slider_blue_converge_y }, |
| 2687 | { "Red Convergence X", -1500, 0, 1500, 1, 3, slider_red_radial_converge_x }, |
| 2688 | { "Red Convergence Y", -1500, 0, 1500, 1, 3, slider_red_radial_converge_y }, |
| 2689 | { "Green Convergence X", -1500, 0, 1500, 1, 3, slider_green_radial_converge_x }, |
| 2690 | { "Green Convergence Y", -1500, 0, 1500, 1, 3, slider_green_radial_converge_y }, |
| 2691 | { "Blue Convergence X", -1500, 0, 1500, 1, 3, slider_blue_radial_converge_x }, |
| 2692 | { "Blue Convergence Y", -1500, 0, 1500, 1, 3, slider_blue_radial_converge_y }, |
| 2693 | { "Red Output from Red Input", -400, 0, 400, 5, 7, slider_red_from_r }, |
| 2694 | { "Red Output from Green Input", -400, 0, 400, 5, 7, slider_red_from_g }, |
| 2695 | { "Red Output from Blue Input", -400, 0, 400, 5, 7, slider_red_from_b }, |
| 2696 | { "Green Output from Red Input", -400, 0, 400, 5, 7, slider_green_from_r }, |
| 2697 | { "Green Output from Green Input", -400, 0, 400, 5, 7, slider_green_from_g }, |
| 2698 | { "Green Output from Blue Input", -400, 0, 400, 5, 7, slider_green_from_b }, |
| 2699 | { "Blue Output from Red Input", -400, 0, 400, 5, 7, slider_blue_from_r }, |
| 2700 | { "Blue Output from Green Input", -400, 0, 400, 5, 7, slider_blue_from_g }, |
| 2701 | { "Blue Output from Blue Input", -400, 0, 400, 5, 7, slider_blue_from_b }, |
| 2702 | { "Saturation", 0, 140, 400, 1, 7, slider_saturation }, |
| 2703 | { "Red DC Offset", -100, 0, 100, 1, 7, slider_red_offset }, |
| 2704 | { "Green DC Offset", -100, 0, 100, 1, 7, slider_green_offset }, |
| 2705 | { "Blue DC Offset", -100, 0, 100, 1, 7, slider_blue_offset }, |
| 2706 | { "Red Scale", -200, 95, 200, 1, 7, slider_red_scale }, |
| 2707 | { "Green Scale", -200, 95, 200, 1, 7, slider_green_scale }, |
| 2708 | { "Blue Scale", -200, 95, 200, 1, 7, slider_blue_scale }, |
| 2709 | { "Red Gamma", -80, 16, 80, 1, 7, slider_red_power }, |
| 2710 | { "Green Gamma", -80, 16, 80, 1, 7, slider_green_power }, |
| 2711 | { "Blue Gamma", -80, 16, 80, 1, 7, slider_blue_power }, |
| 2712 | { "Red Floor", 0, 5, 100, 1, 7, slider_red_floor }, |
| 2713 | { "Green Floor", 0, 5, 100, 1, 7, slider_green_floor }, |
| 2714 | { "Blue Floor", 0, 5, 100, 1, 7, slider_blue_floor }, |
| 2715 | { "Red Phosphor Life", 0, 40, 100, 1, 7, slider_red_phosphor_life }, |
| 2716 | { "Green Phosphor Life", 0, 40, 100, 1, 7, slider_green_phosphor_life }, |
| 2717 | { "Blue Phosphor Life", 0, 40, 100, 1, 7, slider_blue_phosphor_life }, |
| 2718 | { "Bloom Scale", 0, 250, 2000, 5, 7, slider_bloom_scale }, |
| 2719 | { "Bloom Red Overdrive", 0, 250, 2000, 5, 7, slider_bloom_red_overdrive }, |
| 2720 | { "Bloom Green Overdrive", 0, 250, 2000, 5, 7, slider_bloom_green_overdrive }, |
| 2721 | { "Bloom Blue Overdrive", 0, 250, 2000, 5, 7, slider_bloom_blue_overdrive }, |
| 2722 | { "Bloom Level 0 Scale", 0, 100, 100, 1, 7, slider_bloom_lvl0_scale }, |
| 2723 | { "Bloom Level 1 Scale", 0, 21, 100, 1, 7, slider_bloom_lvl1_scale }, |
| 2724 | { "Bloom Level 2 Scale", 0, 19, 100, 1, 7, slider_bloom_lvl2_scale }, |
| 2725 | { "Bloom Level 3 Scale", 0, 17, 100, 1, 7, slider_bloom_lvl3_scale }, |
| 2726 | { "Bloom Level 4 Scale", 0, 15, 100, 1, 7, slider_bloom_lvl4_scale }, |
| 2727 | { "Bloom Level 5 Scale", 0, 14, 100, 1, 7, slider_bloom_lvl5_scale }, |
| 2728 | { "Bloom Level 6 Scale", 0, 13, 100, 1, 7, slider_bloom_lvl6_scale }, |
| 2729 | { "Bloom Level 7 Scale", 0, 12, 100, 1, 7, slider_bloom_lvl7_scale }, |
| 2730 | { "Bloom Level 8 Scale", 0, 11, 100, 1, 7, slider_bloom_lvl8_scale }, |
| 2731 | { "Bloom Level 9 Scale", 0, 10, 100, 1, 7, slider_bloom_lvl9_scale }, |
| 2732 | { "Bloom Level 10 Scale", 0, 9, 100, 1, 7, slider_bloom_lvl10_scale }, |
| 2733 | { NULL, 0, 0, 0, 0, 0, NULL }, |
| 2734 | }; |
| 2735 | |
| 2736 | slider_state *shaders::init_slider_list() |
| 2737 | { |
| 2738 | if (!master_enable || !d3dintf->post_fx_available) |
| 2739 | { |
| 2740 | g_slider_list = NULL; |
| 2741 | return NULL; |
| 2742 | } |
| 2743 | |
| 2744 | slider_state *listhead = NULL; |
| 2745 | slider_state **tailptr = &listhead; |
| 2746 | |
| 2747 | for (int index = 0; s_sliders[index].name != NULL; index++) |
| 2748 | { |
| 2749 | slider_desc *slider = &s_sliders[index]; |
| 2750 | |
| 2751 | int screen_type = machine->first_screen()->screen_type(); |
| 2752 | if ((screen_type == SCREEN_TYPE_VECTOR && (slider->screen_type & SLIDER_SCREEN_TYPE_VECTOR) == SLIDER_SCREEN_TYPE_VECTOR) || |
| 2753 | (screen_type == SCREEN_TYPE_RASTER && (slider->screen_type & SLIDER_SCREEN_TYPE_RASTER) == SLIDER_SCREEN_TYPE_RASTER) || |
| 2754 | (screen_type == SCREEN_TYPE_LCD && (slider->screen_type & SLIDER_SCREEN_TYPE_LCD) == SLIDER_SCREEN_TYPE_LCD)) |
| 2755 | { |
| 2756 | *tailptr = slider_alloc(*machine, slider->name, slider->minval, slider->defval, slider->maxval, slider->step, slider->adjustor, (void*)options); |
| 2757 | tailptr = &(*tailptr)->next; |
| 2758 | } |
| 2759 | } |
| 2760 | |
| 2761 | return listhead; |
| 2762 | } |
| 2763 | |
| 2764 | |
| 2765 | //============================================================ |
| 2766 | // uniform functions |
| 2767 | //============================================================ |
| 2768 | |
| 2769 | uniform::uniform(effect *shader, const char *name, uniform_type type, int id) |
| 2770 | { |
| 2771 | m_shader = shader; |
| 2772 | m_type = type; |
| 2773 | m_next = NULL; |
| 2774 | m_handle = m_shader->get_parameter(NULL, name); |
| 2775 | m_ival = 0; |
| 2776 | memset(m_vec, 0, sizeof(float) * 4); |
| 2777 | m_mval = NULL; |
| 2778 | m_texture = NULL; |
| 2779 | m_id = id; |
| 2780 | |
| 2781 | switch (type) |
| 2782 | { |
| 2783 | case UT_INT: |
| 2784 | case UT_FLOAT: |
| 2785 | case UT_MATRIX: |
| 2786 | case UT_SAMPLER: |
| 2787 | m_count = 1; |
| 2788 | break; |
| 2789 | case UT_VEC2: |
| 2790 | m_count = 2; |
| 2791 | break; |
| 2792 | case UT_VEC3: |
| 2793 | m_count = 3; |
| 2794 | break; |
| 2795 | case UT_VEC4: |
| 2796 | m_count = 4; |
| 2797 | break; |
| 2798 | default: |
| 2799 | m_count = 1; |
| 2800 | break; |
| 2801 | } |
| 2802 | } |
| 2803 | |
| 2804 | void uniform::set_next(uniform *next) |
| 2805 | { |
| 2806 | m_next = next; |
| 2807 | } |
| 2808 | |
| 2809 | void uniform::update() |
| 2810 | { |
| 2811 | if (m_id >= CU_COUNT) |
| 2812 | { |
| 2813 | return; |
| 2814 | } |
| 2815 | |
| 2816 | shaders *shadersys = m_shader->m_shaders; |
| 2817 | hlsl_options *options = shadersys->options; |
| 2818 | renderer *d3d = shadersys->d3d; |
| 2819 | |
| 2820 | switch (m_id) |
| 2821 | { |
| 2822 | case CU_SCREEN_DIMS: |
| 2823 | { |
| 2824 | vec2f screendims = d3d->get_dims(); |
| 2825 | m_shader->set_vector("ScreenDims", 2, &screendims.c.x); |
| 2826 | break; |
| 2827 | } |
| 2828 | case CU_SOURCE_DIMS: |
| 2829 | { |
| 2830 | vec2f sourcedims = shadersys->curr_texture->get_rawdims(); |
| 2831 | m_shader->set_vector("SourceDims", 2, &sourcedims.c.x); |
| 2832 | break; |
| 2833 | } |
| 2834 | case CU_SOURCE_RECT: |
| 2835 | { |
| 2836 | vec2f delta = shadersys->curr_texture->get_uvstop() - shadersys->curr_texture->get_uvstart(); |
| 2837 | m_shader->set_vector("SourceRect", 2, &delta.c.x); |
| 2838 | break; |
| 2839 | } |
| 2840 | case CU_TARGET_DIMS: |
| 2841 | { |
| 2842 | if (shadersys->curr_render_target == NULL) |
| 2843 | { |
| 2844 | float targetdims[2] = { 0.0f, 0.0f }; |
| 2845 | m_shader->set_vector("TargetDims", 2, targetdims); |
| 2846 | } |
| 2847 | else |
| 2848 | { |
| 2849 | float targetdims[2] = { shadersys->curr_render_target->target_width, shadersys->curr_render_target->target_height }; |
| 2850 | m_shader->set_vector("TargetDims", 2, targetdims); |
| 2851 | } |
| 2852 | break; |
| 2853 | } |
| 2854 | case CU_QUAD_DIMS: |
| 2855 | { |
| 2856 | float quaddims[2] = { shadersys->curr_poly->get_prim_width(), shadersys->curr_poly->get_prim_height() }; |
| 2857 | m_shader->set_vector("QuadDims", 2, quaddims); |
| 2858 | break; |
| 2859 | } |
| 2860 | |
| 2861 | case CU_NTSC_CCFREQ: |
| 2862 | m_shader->set_float("CCValue", options->yiq_cc); |
| 2863 | break; |
| 2864 | case CU_NTSC_A: |
| 2865 | m_shader->set_float("AValue", options->yiq_a); |
| 2866 | break; |
| 2867 | case CU_NTSC_B: |
| 2868 | m_shader->set_float("BValue", options->yiq_b); |
| 2869 | break; |
| 2870 | case CU_NTSC_O: |
| 2871 | m_shader->set_float("OValue", options->yiq_o); |
| 2872 | break; |
| 2873 | case CU_NTSC_P: |
| 2874 | m_shader->set_float("PValue", options->yiq_p); |
| 2875 | break; |
| 2876 | case CU_NTSC_NOTCH: |
| 2877 | m_shader->set_float("NotchHalfWidth", options->yiq_n); |
| 2878 | break; |
| 2879 | case CU_NTSC_YFREQ: |
| 2880 | m_shader->set_float("YFreqResponse", options->yiq_y); |
| 2881 | break; |
| 2882 | case CU_NTSC_IFREQ: |
| 2883 | m_shader->set_float("IFreqResponse", options->yiq_i); |
| 2884 | break; |
| 2885 | case CU_NTSC_QFREQ: |
| 2886 | m_shader->set_float("QFreqResponse", options->yiq_q); |
| 2887 | break; |
| 2888 | case CU_NTSC_HTIME: |
| 2889 | m_shader->set_float("ScanTime", options->yiq_scan_time); |
| 2890 | break; |
| 2891 | case CU_NTSC_ENABLE: |
| 2892 | m_shader->set_float("YIQEnable", options->yiq_enable ? 1.0f : 0.0f); |
| 2893 | break; |
| 2894 | |
| 2895 | case CU_COLOR_RED_RATIOS: |
| 2896 | m_shader->set_vector("RedRatios", 3, options->red_ratio); |
| 2897 | break; |
| 2898 | case CU_COLOR_GRN_RATIOS: |
| 2899 | m_shader->set_vector("GrnRatios", 3, options->grn_ratio); |
| 2900 | break; |
| 2901 | case CU_COLOR_BLU_RATIOS: |
| 2902 | m_shader->set_vector("BluRatios", 3, options->blu_ratio); |
| 2903 | break; |
| 2904 | case CU_COLOR_OFFSET: |
| 2905 | m_shader->set_vector("Offset", 3, options->offset); |
| 2906 | break; |
| 2907 | case CU_COLOR_SCALE: |
| 2908 | m_shader->set_vector("Scale", 3, options->scale); |
| 2909 | break; |
| 2910 | case CU_COLOR_SATURATION: |
| 2911 | m_shader->set_float("Saturation", options->saturation); |
| 2912 | break; |
| 2913 | |
| 2914 | case CU_CONVERGE_LINEAR_X: |
| 2915 | m_shader->set_vector("ConvergeX", 3, options->converge_x); |
| 2916 | break; |
| 2917 | case CU_CONVERGE_LINEAR_Y: |
| 2918 | m_shader->set_vector("ConvergeY", 3, options->converge_y); |
| 2919 | break; |
| 2920 | case CU_CONVERGE_RADIAL_X: |
| 2921 | m_shader->set_vector("RadialConvergeX", 3, options->radial_converge_x); |
| 2922 | break; |
| 2923 | case CU_CONVERGE_RADIAL_Y: |
| 2924 | m_shader->set_vector("RadialConvergeY", 3, options->radial_converge_y); |
| 2925 | break; |
| 2926 | |
| 2927 | case CU_FOCUS_SIZE: |
| 2928 | m_shader->set_vector("Defocus", 2, &options->defocus[0]); |
| 2929 | break; |
| 2930 | |
| 2931 | case CU_PHOSPHOR_LIFE: |
| 2932 | m_shader->set_vector("Phosphor", 3, options->phosphor); |
| 2933 | break; |
| 2934 | |
| 2935 | case CU_POST_REFLECTION: |
| 2936 | m_shader->set_float("ReflectionAmount", options->reflection); |
| 2937 | break; |
| 2938 | case CU_POST_VIGNETTING: |
| 2939 | m_shader->set_float("VignettingAmount", options->vignetting); |
| 2940 | break; |
| 2941 | case CU_POST_CURVATURE: |
| 2942 | m_shader->set_float("CurvatureAmount", options->curvature); |
| 2943 | break; |
| 2944 | case CU_POST_ROUND_CORNER: |
| 2945 | m_shader->set_float("RoundCornerAmount", options->round_corner); |
| 2946 | break; |
| 2947 | case CU_POST_SMOOTH_BORDER: |
| 2948 | m_shader->set_float("SmoothBorderAmount", options->smooth_border); |
| 2949 | break; |
| 2950 | case CU_POST_SHADOW_ALPHA: |
| 2951 | m_shader->set_float("ShadowAlpha", shadersys->shadow_texture == NULL ? 0.0f : options->shadow_mask_alpha); |
| 2952 | break; |
| 2953 | case CU_POST_SHADOW_COUNT: |
| 2954 | { |
| 2955 | float shadowcount[2] = { options->shadow_mask_count_x, options->shadow_mask_count_y }; |
| 2956 | m_shader->set_vector("ShadowCount", 2, shadowcount); |
| 2957 | break; |
| 2958 | } |
| 2959 | case CU_POST_SHADOW_UV: |
| 2960 | { |
| 2961 | float shadowuv[2] = { options->shadow_mask_u_size, options->shadow_mask_v_size }; |
| 2962 | m_shader->set_vector("ShadowUV", 2, shadowuv); |
| 2963 | break; |
| 2964 | } |
| 2965 | case CU_POST_SHADOW_UV_OFFSET: |
| 2966 | { |
| 2967 | float shadowuv[2] = { options->shadow_mask_u_offset, options->shadow_mask_v_offset }; |
| 2968 | m_shader->set_vector("ShadowUVOffset", 2, shadowuv); |
| 2969 | break; |
| 2970 | } |
| 2971 | case CU_POST_SHADOW_DIMS: |
| 2972 | { |
| 2973 | vec2f shadow_dims; |
| 2974 | |
| 2975 | if (shadersys->shadow_texture) |
| 2976 | { |
| 2977 | shadow_dims = shadersys->shadow_texture->get_rawdims(); |
| 2978 | } |
| 2979 | else |
| 2980 | { |
| 2981 | shadow_dims.c.x = 1.0f; |
| 2982 | shadow_dims.c.y = 1.0f; |
| 2983 | } |
| 2984 | |
| 2985 | m_shader->set_vector("ShadowDims", 2, &shadow_dims.c.x); |
| 2986 | break; |
| 2987 | } |
| 2988 | case CU_POST_SCANLINE_ALPHA: |
| 2989 | m_shader->set_float("ScanlineAlpha", options->scanline_alpha); |
| 2990 | break; |
| 2991 | case CU_POST_SCANLINE_SCALE: |
| 2992 | m_shader->set_float("ScanlineScale", options->scanline_scale); |
| 2993 | break; |
| 2994 | case CU_POST_SCANLINE_HEIGHT: |
| 2995 | m_shader->set_float("ScanlineHeight", options->scanline_height); |
| 2996 | break; |
| 2997 | case CU_POST_SCANLINE_BRIGHT_SCALE: |
| 2998 | m_shader->set_float("ScanlineBrightScale", options->scanline_bright_scale); |
| 2999 | break; |
| 3000 | case CU_POST_SCANLINE_BRIGHT_OFFSET: |
| 3001 | m_shader->set_float("ScanlineBrightOffset", options->scanline_bright_offset); |
| 3002 | break; |
| 3003 | case CU_POST_POWER: |
| 3004 | m_shader->set_vector("Power", 3, options->power); |
| 3005 | break; |
| 3006 | case CU_POST_FLOOR: |
| 3007 | m_shader->set_vector("Floor", 3, options->floor); |
| 3008 | break; |
| 3009 | |
| 3010 | case CU_BLOOM_RESCALE: |
| 3011 | m_shader->set_float("BloomRescale", options->bloom_scale); |
| 3012 | break; |
| 3013 | case CU_BLOOM_LVL0123_WEIGHTS: |
| 3014 | { |
| 3015 | float weight0123[4] = { options->bloom_level0_weight, options->bloom_level1_weight, options->bloom_level2_weight, options->bloom_level3_weight }; |
| 3016 | m_shader->set_vector("Level0123Weight", 4, weight0123); |
| 3017 | break; |
| 3018 | } |
| 3019 | case CU_BLOOM_LVL4567_WEIGHTS: |
| 3020 | { |
| 3021 | float weight4567[4] = { options->bloom_level4_weight, options->bloom_level5_weight, options->bloom_level6_weight, options->bloom_level7_weight }; |
| 3022 | m_shader->set_vector("Level4567Weight", 4, weight4567); |
| 3023 | break; |
| 3024 | } |
| 3025 | case CU_BLOOM_LVL89A_WEIGHTS: |
| 3026 | { |
| 3027 | float weight89A[3] = { options->bloom_level8_weight, options->bloom_level9_weight, options->bloom_level10_weight }; |
| 3028 | m_shader->set_vector("Level89AWeight", 3, weight89A); |
| 3029 | break; |
| 3030 | } |
| 3031 | } |
| 3032 | } |
| 3033 | |
| 3034 | void uniform::set(float x, float y, float z, float w) |
| 3035 | { |
| 3036 | m_vec[0] = x; |
| 3037 | m_vec[1] = y; |
| 3038 | m_vec[2] = z; |
| 3039 | m_vec[3] = w; |
| 3040 | } |
| 3041 | |
| 3042 | void uniform::set(float x, float y, float z) |
| 3043 | { |
| 3044 | m_vec[0] = x; |
| 3045 | m_vec[1] = y; |
| 3046 | m_vec[2] = z; |
| 3047 | } |
| 3048 | |
| 3049 | void uniform::set(float x, float y) |
| 3050 | { |
| 3051 | m_vec[0] = x; |
| 3052 | m_vec[1] = y; |
| 3053 | } |
| 3054 | |
| 3055 | void uniform::set(float x) |
| 3056 | { |
| 3057 | m_vec[0] = x; |
| 3058 | } |
| 3059 | |
| 3060 | void uniform::set(int x) |
| 3061 | { |
| 3062 | m_ival = x; |
| 3063 | } |
| 3064 | |
| 3065 | void uniform::set(matrix *mat) |
| 3066 | { |
| 3067 | m_mval = mat; |
| 3068 | } |
| 3069 | |
| 3070 | void uniform::set(texture *tex) |
| 3071 | { |
| 3072 | m_texture = tex; |
| 3073 | } |
| 3074 | |
| 3075 | void uniform::upload() |
| 3076 | { |
| 3077 | switch (m_type) |
| 3078 | { |
| 3079 | case UT_INT: |
| 3080 | m_shader->set_int(m_handle, m_ival); |
| 3081 | break; |
| 3082 | case UT_FLOAT: |
| 3083 | m_shader->set_float(m_handle, m_vec[0]); |
| 3084 | break; |
| 3085 | case UT_VEC2: |
| 3086 | case UT_VEC3: |
| 3087 | case UT_VEC4: |
| 3088 | m_shader->set_vector(m_handle, m_count, m_vec); |
| 3089 | break; |
| 3090 | case UT_MATRIX: |
| 3091 | m_shader->set_matrix(m_handle, m_mval); |
| 3092 | break; |
| 3093 | case UT_SAMPLER: |
| 3094 | m_shader->set_texture(m_handle, m_texture); |
| 3095 | break; |
| 3096 | } |
| 3097 | } |
| 3098 | |
| 3099 | |
| 3100 | //============================================================ |
| 3101 | // effect functions |
| 3102 | //============================================================ |
| 3103 | |
| 3104 | effect::effect(shaders *shadersys, device *dev, const char *name, const char *path) |
| 3105 | { |
| 3106 | IDirect3DDevice9 *device = (IDirect3DDevice9 *)dev; |
| 3107 | LPD3DXBUFFER buffer_errors = NULL; |
| 3108 | |
| 3109 | m_shaders = shadersys; |
| 3110 | m_uniform_head = NULL; |
| 3111 | m_uniform_tail = NULL; |
| 3112 | m_effect = NULL; |
| 3113 | m_valid = false; |
| 3114 | |
| 3115 | char name_cstr[1024]; |
| 3116 | sprintf(name_cstr, "%s\\%s", path, name); |
| 3117 | TCHAR *effect_name = tstring_from_utf8(name_cstr); |
| 3118 | |
| 3119 | HRESULT hr = (*g_load_effect)(device, effect_name, NULL, NULL, 0, NULL, &m_effect, &buffer_errors); |
| 3120 | if (FAILED(hr)) |
| 3121 | { |
| 3122 | if (buffer_errors != NULL) |
| 3123 | { |
| 3124 | LPVOID compile_errors = buffer_errors->GetBufferPointer(); |
| 3125 | printf("Unable to compile shader: %s\n", (const char*)compile_errors); fflush(stdout); |
| 3126 | } |
| 3127 | else |
| 3128 | { |
| 3129 | printf("Shader %s is missing, corrupt or cannot be compiled.\n", (const char*)name); fflush(stdout); |
| 3130 | } |
| 3131 | } |
| 3132 | else |
| 3133 | { |
| 3134 | m_valid = true; |
| 3135 | } |
| 3136 | |
| 3137 | osd_free(effect_name); |
| 3138 | } |
| 3139 | |
| 3140 | effect::~effect() |
| 3141 | { |
| 3142 | m_effect->Release(); |
| 3143 | m_effect = NULL; |
| 3144 | uniform *curr = m_uniform_head; |
| 3145 | while (curr != NULL) |
| 3146 | { |
| 3147 | uniform *next = curr->get_next(); |
| 3148 | delete curr; |
| 3149 | curr = next; |
| 3150 | } |
| 3151 | m_uniform_head = NULL; |
| 3152 | m_uniform_tail = NULL; |
| 3153 | } |
| 3154 | |
| 3155 | void effect::add_uniform(const char *name, uniform::uniform_type type, int id) |
| 3156 | { |
| 3157 | uniform *newuniform = new uniform(this, name, type, id); |
| 3158 | if (newuniform == NULL) |
| 3159 | { |
| 3160 | return; |
| 3161 | } |
| 3162 | |
| 3163 | if (m_uniform_head == NULL) |
| 3164 | { |
| 3165 | m_uniform_head = newuniform; |
| 3166 | } |
| 3167 | if (m_uniform_tail != NULL) |
| 3168 | { |
| 3169 | m_uniform_tail->set_next(newuniform); |
| 3170 | } |
| 3171 | m_uniform_tail = newuniform; |
| 3172 | } |
| 3173 | |
| 3174 | void effect::update_uniforms() |
| 3175 | { |
| 3176 | uniform *curr = m_uniform_head; |
| 3177 | while(curr != NULL) |
| 3178 | { |
| 3179 | curr->update(); |
| 3180 | curr = curr->get_next(); |
| 3181 | } |
| 3182 | } |
| 3183 | |
| 3184 | void effect::begin(UINT *passes, DWORD flags) |
| 3185 | { |
| 3186 | m_effect->Begin(passes, flags); |
| 3187 | } |
| 3188 | |
| 3189 | void effect::end() |
| 3190 | { |
| 3191 | m_effect->End(); |
| 3192 | } |
| 3193 | |
| 3194 | void effect::begin_pass(UINT pass) |
| 3195 | { |
| 3196 | m_effect->BeginPass(pass); |
| 3197 | } |
| 3198 | |
| 3199 | void effect::end_pass() |
| 3200 | { |
| 3201 | m_effect->EndPass(); |
| 3202 | } |
| 3203 | |
| 3204 | void effect::set_technique(const char *name) |
| 3205 | { |
| 3206 | m_effect->SetTechnique(name); |
| 3207 | } |
| 3208 | |
| 3209 | void effect::set_vector(D3DXHANDLE param, int count, float *vector) |
| 3210 | { |
| 3211 | static D3DXVECTOR4 out_vector; |
| 3212 | if (count > 0) |
| 3213 | { |
| 3214 | out_vector.x = vector[0]; |
| 3215 | } |
| 3216 | if (count > 1) |
| 3217 | { |
| 3218 | out_vector.y = vector[1]; |
| 3219 | } |
| 3220 | if (count > 2) |
| 3221 | { |
| 3222 | out_vector.z = vector[2]; |
| 3223 | } |
| 3224 | if (count > 3) |
| 3225 | { |
| 3226 | out_vector.w = vector[3]; |
| 3227 | } |
| 3228 | m_effect->SetVector(param, &out_vector); |
| 3229 | } |
| 3230 | |
| 3231 | void effect::set_float(D3DXHANDLE param, float value) |
| 3232 | { |
| 3233 | m_effect->SetFloat(param, value); |
| 3234 | } |
| 3235 | |
| 3236 | void effect::set_int(D3DXHANDLE param, int value) |
| 3237 | { |
| 3238 | m_effect->SetInt(param, value); |
| 3239 | } |
| 3240 | |
| 3241 | void effect::set_bool(D3DXHANDLE param, bool value) |
| 3242 | { |
| 3243 | m_effect->SetBool(param, value); |
| 3244 | } |
| 3245 | |
| 3246 | void effect::set_matrix(D3DXHANDLE param, matrix *matrix) |
| 3247 | { |
| 3248 | m_effect->SetMatrix(param, (D3DXMATRIX*)matrix); |
| 3249 | } |
| 3250 | |
| 3251 | void effect::set_texture(D3DXHANDLE param, texture *tex) |
| 3252 | { |
| 3253 | m_effect->SetTexture(param, (IDirect3DTexture9*)tex); |
| 3254 | } |
| 3255 | |
| 3256 | D3DXHANDLE effect::get_parameter(D3DXHANDLE param, const char *name) |
| 3257 | { |
| 3258 | return m_effect->GetParameterByName(param, name); |
| 3259 | } |
| 3260 | |
| 3261 | ULONG effect::release() |
| 3262 | { |
| 3263 | return m_effect->Release(); |
| 3264 | } |
| 3265 | |
| 3266 | } |
| 3267 | |
| 3268 | |
| 3269 | //============================================================ |
| 3270 | // get_slider_list |
| 3271 | //============================================================ |
| 3272 | |
| 3273 | void *windows_osd_interface::get_slider_list() |
| 3274 | { |
| 3275 | return (void*)g_slider_list; |
| 3276 | } |
| 3277 | |
| 3278 | |
| 3279 | // NOTE: The function below is taken directly from src/emu/video.c and should likely be moved into a global helper function. |
| 3280 | //------------------------------------------------- |
| 3281 | // open_next - open the next non-existing file of |
| 3282 | // type filetype according to our numbering |
| 3283 | // scheme |
| 3284 | //------------------------------------------------- |
| 3285 | |
| 3286 | static file_error open_next(d3d::renderer *d3d, emu_file &file, const char *templ, const char *extension, int idx) |
| 3287 | { |
| 3288 | UINT32 origflags = file.openflags(); |
| 3289 | |
| 3290 | // handle defaults |
| 3291 | const char *snapname = templ ? templ : d3d->window().machine().options().snap_name(); |
| 3292 | |
| 3293 | if (snapname == NULL || snapname[0] == 0) |
| 3294 | { |
| 3295 | snapname = "%g/%i"; |
| 3296 | } |
| 3297 | std::string snapstr(snapname); |
| 3298 | |
| 3299 | // strip any extension in the provided name |
| 3300 | int index = snapstr.find_last_of('.'); |
| 3301 | if (index != -1) |
| 3302 | { |
| 3303 | snapstr.substr(0, index); |
| 3304 | } |
| 3305 | |
| 3306 | // handle %d in the template (for image devices) |
| 3307 | std::string snapdev("%d_"); |
| 3308 | int pos = snapstr.find(snapdev,0); |
| 3309 | |
| 3310 | if (pos != -1) |
| 3311 | { |
| 3312 | // if more %d are found, revert to default and ignore them all |
| 3313 | if (snapstr.find(snapdev, pos + 3) != -1) |
| 3314 | { |
| 3315 | snapstr.assign("%g/%i"); |
| 3316 | } |
| 3317 | // else if there is a single %d, try to create the correct snapname |
| 3318 | else |
| 3319 | { |
| 3320 | int name_found = 0; |
| 3321 | |
| 3322 | // find length of the device name |
| 3323 | int end1 = snapstr.find("/", pos + 3); |
| 3324 | int end2 = snapstr.find("%", pos + 3); |
| 3325 | int end = -1; |
| 3326 | |
| 3327 | if ((end1 != -1) && (end2 != -1)) |
| 3328 | { |
| 3329 | end = MIN(end1, end2); |
| 3330 | } |
| 3331 | else if (end1 != -1) |
| 3332 | { |
| 3333 | end = end1; |
| 3334 | } |
| 3335 | else if (end2 != -1) |
| 3336 | { |
| 3337 | end = end2; |
| 3338 | } |
| 3339 | else |
| 3340 | { |
| 3341 | end = snapstr.length(); |
| 3342 | } |
| 3343 | |
| 3344 | if (end - pos < 3) |
| 3345 | { |
| 3346 | fatalerror("Something very wrong is going on!!!\n"); |
| 3347 | } |
| 3348 | |
| 3349 | // copy the device name to a string |
| 3350 | std::string snapdevname; |
| 3351 | snapdevname.assign(snapstr.substr(pos + 3, end - pos - 3)); |
| 3352 | |
| 3353 | // verify that there is such a device for this system |
| 3354 | image_interface_iterator iter(d3d->window().machine().root_device()); |
| 3355 | for (device_image_interface *image = iter.first(); image != NULL; iter.next()) |
| 3356 | { |
| 3357 | // get the device name |
| 3358 | std::string tempdevname(image->brief_instance_name()); |
| 3359 | |
| 3360 | if (snapdevname.compare(tempdevname) == 0) |
| 3361 | { |
| 3362 | // verify that such a device has an image mounted |
| 3363 | if (image->basename() != NULL) |
| 3364 | { |
| 3365 | std::string filename(image->basename()); |
| 3366 | |
| 3367 | // strip extension |
| 3368 | filename.substr(0, filename.find_last_of('.')); |
| 3369 | |
| 3370 | // setup snapname and remove the %d_ |
| 3371 | strreplace(snapstr, snapdevname.c_str(), filename.c_str()); |
| 3372 | snapstr.erase(pos, 3); |
| 3373 | |
| 3374 | name_found = 1; |
| 3375 | } |
| 3376 | } |
| 3377 | } |
| 3378 | |
| 3379 | // or fallback to default |
| 3380 | if (name_found == 0) |
| 3381 | { |
| 3382 | snapstr.assign("%g/%i"); |
| 3383 | } |
| 3384 | } |
| 3385 | } |
| 3386 | |
| 3387 | // add our own index |
| 3388 | // add our own extension |
| 3389 | snapstr.append(".").append(extension); |
| 3390 | |
| 3391 | // substitute path and gamename up front |
| 3392 | strreplace(snapstr, "/", PATH_SEPARATOR); |
| 3393 | strreplace(snapstr, "%g", d3d->window().machine().basename()); |
| 3394 | |
| 3395 | // determine if the template has an index; if not, we always use the same name |
| 3396 | std::string fname; |
| 3397 | if (snapstr.find("%i") == -1) |
| 3398 | { |
| 3399 | fname.assign(snapstr); |
| 3400 | } |
| 3401 | |
| 3402 | // otherwise, we scan for the next available filename |
| 3403 | else |
| 3404 | { |
| 3405 | // try until we succeed |
| 3406 | std::string seqtext; |
| 3407 | file.set_openflags(OPEN_FLAG_READ); |
| 3408 | for (int seq = 0; ; seq++) |
| 3409 | { |
| 3410 | // build up the filename |
| 3411 | strprintf(seqtext, "%04d_%d", seq, idx); |
| 3412 | strreplace(fname.assign(snapstr), "%i", seqtext.c_str()); |
| 3413 | |
| 3414 | // try to open the file; stop when we fail |
| 3415 | file_error filerr = file.open(fname.c_str()); |
| 3416 | if (filerr != FILERR_NONE) |
| 3417 | { |
| 3418 | break; |
| 3419 | } |
| 3420 | } |
| 3421 | } |
| 3422 | |
| 3423 | // create the final file |
| 3424 | file.set_openflags(origflags); |
| 3425 | return file.open(fname.c_str()); |
| 3426 | } |
trunk/src/osd/modules/render/drawd3d.c
| r250287 | r250288 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Aaron Giles |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // drawd3d.c - Win32 Direct3D implementation |
| 6 | | // |
| 7 | | //============================================================ |
| 8 | | |
| 9 | | // Useful info: |
| 10 | | // Windows XP/2003 shipped with DirectX 8.1 |
| 11 | | // Windows 2000 shipped with DirectX 7a |
| 12 | | // Windows 98SE shipped with DirectX 6.1a |
| 13 | | // Windows 98 shipped with DirectX 5 |
| 14 | | // Windows NT shipped with DirectX 3.0a |
| 15 | | // Windows 95 shipped with DirectX 2 |
| 16 | | |
| 17 | | // standard windows headers |
| 18 | | #define WIN32_LEAN_AND_MEAN |
| 19 | | #include <windows.h> |
| 20 | | #include <tchar.h> |
| 21 | | #include <mmsystem.h> |
| 22 | | #include <d3d9.h> |
| 23 | | #include <d3dx9.h> |
| 24 | | #include <math.h> |
| 25 | | #undef interface |
| 26 | | |
| 27 | | // MAME headers |
| 28 | | #include "emu.h" |
| 29 | | #include "render.h" |
| 30 | | #include "ui/ui.h" |
| 31 | | #include "rendutil.h" |
| 32 | | #include "options.h" |
| 33 | | #include "emuopts.h" |
| 34 | | #include "aviio.h" |
| 35 | | #include "png.h" |
| 36 | | |
| 37 | | // MAMEOS headers |
| 38 | | #include "modules/render/d3d/d3dintf.h" |
| 39 | | #include "winmain.h" |
| 40 | | #include "window.h" |
| 41 | | #include "config.h" |
| 42 | | #include "strconv.h" |
| 43 | | #include "modules/render/d3d/d3dcomm.h" |
| 44 | | #include "drawd3d.h" |
| 45 | | |
| 46 | | |
| 47 | | //============================================================ |
| 48 | | // DEBUGGING |
| 49 | | //============================================================ |
| 50 | | |
| 51 | | extern void mtlog_add(const char *event); |
| 52 | | |
| 53 | | |
| 54 | | //============================================================ |
| 55 | | // CONSTANTS |
| 56 | | //============================================================ |
| 57 | | |
| 58 | | #define ENABLE_BORDER_PIX (1) |
| 59 | | |
| 60 | | enum |
| 61 | | { |
| 62 | | TEXTURE_TYPE_PLAIN, |
| 63 | | TEXTURE_TYPE_DYNAMIC, |
| 64 | | TEXTURE_TYPE_SURFACE |
| 65 | | }; |
| 66 | | |
| 67 | | |
| 68 | | //============================================================ |
| 69 | | // MACROS |
| 70 | | //============================================================ |
| 71 | | |
| 72 | | #define FSWAP(var1, var2) do { float temp = var1; var1 = var2; var2 = temp; } while (0) |
| 73 | | |
| 74 | | |
| 75 | | //============================================================ |
| 76 | | // GLOBALS |
| 77 | | //============================================================ |
| 78 | | |
| 79 | | static const line_aa_step line_aa_1step[] = |
| 80 | | { |
| 81 | | { 0.00f, 0.00f, 1.00f }, |
| 82 | | { 0 } |
| 83 | | }; |
| 84 | | |
| 85 | | static const line_aa_step line_aa_4step[] = |
| 86 | | { |
| 87 | | { -0.25f, 0.00f, 0.25f }, |
| 88 | | { 0.25f, 0.00f, 0.25f }, |
| 89 | | { 0.00f, -0.25f, 0.25f }, |
| 90 | | { 0.00f, 0.25f, 0.25f }, |
| 91 | | { 0 } |
| 92 | | }; |
| 93 | | |
| 94 | | |
| 95 | | //============================================================ |
| 96 | | // INLINES |
| 97 | | //============================================================ |
| 98 | | |
| 99 | | INLINE BOOL GetClientRectExceptMenu(HWND hWnd, PRECT pRect, BOOL fullscreen) |
| 100 | | { |
| 101 | | static HMENU last_menu; |
| 102 | | static RECT last_rect; |
| 103 | | static RECT cached_rect; |
| 104 | | HMENU menu = GetMenu(hWnd); |
| 105 | | BOOL result = GetClientRect(hWnd, pRect); |
| 106 | | |
| 107 | | if (!fullscreen || !menu) |
| 108 | | return result; |
| 109 | | |
| 110 | | // to avoid flicker use cache if we can use |
| 111 | | if (last_menu != menu || memcmp(&last_rect, pRect, sizeof *pRect) != 0) |
| 112 | | { |
| 113 | | last_menu = menu; |
| 114 | | last_rect = *pRect; |
| 115 | | |
| 116 | | SetMenu(hWnd, NULL); |
| 117 | | result = GetClientRect(hWnd, &cached_rect); |
| 118 | | SetMenu(hWnd, menu); |
| 119 | | } |
| 120 | | |
| 121 | | *pRect = cached_rect; |
| 122 | | return result; |
| 123 | | } |
| 124 | | |
| 125 | | |
| 126 | | INLINE UINT32 ycc_to_rgb(UINT8 y, UINT8 cb, UINT8 cr) |
| 127 | | { |
| 128 | | /* original equations: |
| 129 | | |
| 130 | | C = Y - 16 |
| 131 | | D = Cb - 128 |
| 132 | | E = Cr - 128 |
| 133 | | |
| 134 | | R = clip(( 298 * C + 409 * E + 128) >> 8) |
| 135 | | G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8) |
| 136 | | B = clip(( 298 * C + 516 * D + 128) >> 8) |
| 137 | | |
| 138 | | R = clip(( 298 * (Y - 16) + 409 * (Cr - 128) + 128) >> 8) |
| 139 | | G = clip(( 298 * (Y - 16) - 100 * (Cb - 128) - 208 * (Cr - 128) + 128) >> 8) |
| 140 | | B = clip(( 298 * (Y - 16) + 516 * (Cb - 128) + 128) >> 8) |
| 141 | | |
| 142 | | R = clip(( 298 * Y - 298 * 16 + 409 * Cr - 409 * 128 + 128) >> 8) |
| 143 | | G = clip(( 298 * Y - 298 * 16 - 100 * Cb + 100 * 128 - 208 * Cr + 208 * 128 + 128) >> 8) |
| 144 | | B = clip(( 298 * Y - 298 * 16 + 516 * Cb - 516 * 128 + 128) >> 8) |
| 145 | | |
| 146 | | R = clip(( 298 * Y - 298 * 16 + 409 * Cr - 409 * 128 + 128) >> 8) |
| 147 | | G = clip(( 298 * Y - 298 * 16 - 100 * Cb + 100 * 128 - 208 * Cr + 208 * 128 + 128) >> 8) |
| 148 | | B = clip(( 298 * Y - 298 * 16 + 516 * Cb - 516 * 128 + 128) >> 8) |
| 149 | | */ |
| 150 | | int r, g, b, common; |
| 151 | | |
| 152 | | common = 298 * y - 298 * 16; |
| 153 | | r = (common + 409 * cr - 409 * 128 + 128) >> 8; |
| 154 | | g = (common - 100 * cb + 100 * 128 - 208 * cr + 208 * 128 + 128) >> 8; |
| 155 | | b = (common + 516 * cb - 516 * 128 + 128) >> 8; |
| 156 | | |
| 157 | | if (r < 0) r = 0; |
| 158 | | else if (r > 255) r = 255; |
| 159 | | if (g < 0) g = 0; |
| 160 | | else if (g > 255) g = 255; |
| 161 | | if (b < 0) b = 0; |
| 162 | | else if (b > 255) b = 255; |
| 163 | | |
| 164 | | return rgb_t(0xff, r, g, b); |
| 165 | | } |
| 166 | | |
| 167 | | |
| 168 | | //============================================================ |
| 169 | | // drawd3d_init |
| 170 | | //============================================================ |
| 171 | | |
| 172 | | static d3d::base * d3dintf; // FIX ME |
| 173 | | |
| 174 | | |
| 175 | | //============================================================ |
| 176 | | // PROTOTYPES |
| 177 | | //============================================================ |
| 178 | | |
| 179 | | // core functions |
| 180 | | static void drawd3d_exit(void); |
| 181 | | |
| 182 | | |
| 183 | | //============================================================ |
| 184 | | // drawd3d_window_init |
| 185 | | //============================================================ |
| 186 | | |
| 187 | | int d3d::renderer::create() |
| 188 | | { |
| 189 | | if (!initialize()) |
| 190 | | { |
| 191 | | destroy(); |
| 192 | | osd_printf_error("Unable to initialize Direct3D.\n"); |
| 193 | | return 1; |
| 194 | | } |
| 195 | | |
| 196 | | return 0; |
| 197 | | } |
| 198 | | |
| 199 | | |
| 200 | | //============================================================ |
| 201 | | // drawd3d_exit |
| 202 | | //============================================================ |
| 203 | | |
| 204 | | static void drawd3d_exit(void) |
| 205 | | { |
| 206 | | if (d3dintf != NULL) |
| 207 | | (*d3dintf->d3d.release)(d3dintf); |
| 208 | | } |
| 209 | | |
| 210 | | void d3d::renderer::toggle_fsfx() |
| 211 | | { |
| 212 | | set_restarting(true); |
| 213 | | } |
| 214 | | |
| 215 | | void d3d::renderer::record() |
| 216 | | { |
| 217 | | get_shaders()->window_record(); |
| 218 | | } |
| 219 | | |
| 220 | | void d3d::renderer::save() |
| 221 | | { |
| 222 | | get_shaders()->window_save(); |
| 223 | | } |
| 224 | | |
| 225 | | |
| 226 | | //============================================================ |
| 227 | | // drawd3d_window_destroy |
| 228 | | //============================================================ |
| 229 | | |
| 230 | | void d3d::renderer::destroy() |
| 231 | | { |
| 232 | | if (get_shaders() != NULL && get_shaders()->recording()) |
| 233 | | get_shaders()->window_record(); |
| 234 | | |
| 235 | | } |
| 236 | | |
| 237 | | |
| 238 | | //============================================================ |
| 239 | | // drawd3d_window_get_primitives |
| 240 | | //============================================================ |
| 241 | | |
| 242 | | render_primitive_list *d3d::renderer::get_primitives() |
| 243 | | { |
| 244 | | RECT client; |
| 245 | | |
| 246 | | GetClientRectExceptMenu(window().m_hwnd, &client, window().fullscreen()); |
| 247 | | if (rect_width(&client) > 0 && rect_height(&client) > 0) |
| 248 | | { |
| 249 | | window().target()->set_bounds(rect_width(&client), rect_height(&client), window().aspect()); |
| 250 | | window().target()->set_max_update_rate((get_refresh() == 0) ? get_origmode().RefreshRate : get_refresh()); |
| 251 | | } |
| 252 | | return &window().target()->get_primitives(); |
| 253 | | } |
| 254 | | |
| 255 | | |
| 256 | | //============================================================ |
| 257 | | // drawnone_create |
| 258 | | //============================================================ |
| 259 | | |
| 260 | | static osd_renderer *drawd3d_create(osd_window *window) |
| 261 | | { |
| 262 | | return global_alloc(d3d::renderer(window)); |
| 263 | | } |
| 264 | | |
| 265 | | int drawd3d_init(running_machine &machine, osd_draw_callbacks *callbacks) |
| 266 | | { |
| 267 | | d3dintf = NULL; |
| 268 | | |
| 269 | | // Use Direct3D9 |
| 270 | | d3dintf = d3d::drawd3d9_init(); |
| 271 | | |
| 272 | | // if we failed, note the error |
| 273 | | if (d3dintf == NULL) |
| 274 | | { |
| 275 | | osd_printf_error("Unable to initialize Direct3D.\n"); |
| 276 | | return 1; |
| 277 | | } |
| 278 | | |
| 279 | | // fill in the callbacks |
| 280 | | memset(callbacks, 0, sizeof(*callbacks)); |
| 281 | | callbacks->exit = drawd3d_exit; |
| 282 | | callbacks->create = drawd3d_create; |
| 283 | | return 0; |
| 284 | | } |
| 285 | | |
| 286 | | |
| 287 | | //============================================================ |
| 288 | | // drawd3d_window_draw |
| 289 | | //============================================================ |
| 290 | | |
| 291 | | int d3d::renderer::draw(const int update) |
| 292 | | { |
| 293 | | int check = pre_window_draw_check(); |
| 294 | | if (check >= 0) |
| 295 | | return check; |
| 296 | | |
| 297 | | begin_frame(); |
| 298 | | process_primitives(); |
| 299 | | end_frame(); |
| 300 | | |
| 301 | | return 0; |
| 302 | | } |
| 303 | | |
| 304 | | namespace d3d |
| 305 | | { |
| 306 | | void renderer::set_texture(texture_info *texture) |
| 307 | | { |
| 308 | | if (texture != m_last_texture) |
| 309 | | { |
| 310 | | m_last_texture = texture; |
| 311 | | m_last_texture_flags = (texture == NULL ? 0 : texture->get_flags()); |
| 312 | | HRESULT result = (*d3dintf->device.set_texture)(m_device, 0, (texture == NULL) ? get_default_texture()->get_finaltex() : texture->get_finaltex()); |
| 313 | | m_shaders->set_texture(texture); |
| 314 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture call\n", (int)result); |
| 315 | | } |
| 316 | | } |
| 317 | | |
| 318 | | void renderer::set_filter(int filter) |
| 319 | | { |
| 320 | | if (filter != m_last_filter) |
| 321 | | { |
| 322 | | m_last_filter = filter; |
| 323 | | HRESULT result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MINFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT); |
| 324 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result); |
| 325 | | result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MAGFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT); |
| 326 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result); |
| 327 | | result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MINFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT); |
| 328 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result); |
| 329 | | result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MAGFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT); |
| 330 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result); |
| 331 | | } |
| 332 | | } |
| 333 | | |
| 334 | | void renderer::set_wrap(D3DTEXTUREADDRESS wrap) |
| 335 | | { |
| 336 | | if (wrap != m_last_wrap) |
| 337 | | { |
| 338 | | m_last_wrap = wrap; |
| 339 | | HRESULT result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSU, wrap); |
| 340 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result); |
| 341 | | result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSV, wrap); |
| 342 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result); |
| 343 | | result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSU, wrap); |
| 344 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result); |
| 345 | | result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSV, wrap); |
| 346 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result); |
| 347 | | } |
| 348 | | } |
| 349 | | |
| 350 | | void renderer::set_modmode(DWORD modmode) |
| 351 | | { |
| 352 | | if (modmode != m_last_modmode) |
| 353 | | { |
| 354 | | m_last_modmode = modmode; |
| 355 | | HRESULT result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, D3DTSS_COLOROP, modmode); |
| 356 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result); |
| 357 | | result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, D3DTSS_COLOROP, modmode); |
| 358 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result); |
| 359 | | } |
| 360 | | } |
| 361 | | |
| 362 | | void renderer::set_blendmode(int blendmode) |
| 363 | | { |
| 364 | | int blendenable; |
| 365 | | int blendop; |
| 366 | | int blendsrc; |
| 367 | | int blenddst; |
| 368 | | |
| 369 | | // choose the parameters |
| 370 | | switch (blendmode) |
| 371 | | { |
| 372 | | default: |
| 373 | | case BLENDMODE_NONE: blendenable = FALSE; blendop = D3DBLENDOP_ADD; blendsrc = D3DBLEND_SRCALPHA; blenddst = D3DBLEND_INVSRCALPHA; break; |
| 374 | | case BLENDMODE_ALPHA: blendenable = TRUE; blendop = D3DBLENDOP_ADD; blendsrc = D3DBLEND_SRCALPHA; blenddst = D3DBLEND_INVSRCALPHA; break; |
| 375 | | case BLENDMODE_RGB_MULTIPLY: blendenable = TRUE; blendop = D3DBLENDOP_ADD; blendsrc = D3DBLEND_DESTCOLOR; blenddst = D3DBLEND_ZERO; break; |
| 376 | | case BLENDMODE_ADD: blendenable = TRUE; blendop = D3DBLENDOP_ADD; blendsrc = D3DBLEND_SRCALPHA; blenddst = D3DBLEND_ONE; break; |
| 377 | | } |
| 378 | | |
| 379 | | // adjust the bits that changed |
| 380 | | if (blendenable != m_last_blendenable) |
| 381 | | { |
| 382 | | m_last_blendenable = blendenable; |
| 383 | | HRESULT result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ALPHABLENDENABLE, blendenable); |
| 384 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_state call\n", (int)result); |
| 385 | | } |
| 386 | | |
| 387 | | if (blendop != m_last_blendop) |
| 388 | | { |
| 389 | | m_last_blendop = blendop; |
| 390 | | HRESULT result = (*d3dintf->device.set_render_state)(m_device, D3DRS_BLENDOP, blendop); |
| 391 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_state call\n", (int)result); |
| 392 | | } |
| 393 | | |
| 394 | | if (blendsrc != m_last_blendsrc) |
| 395 | | { |
| 396 | | m_last_blendsrc = blendsrc; |
| 397 | | HRESULT result = (*d3dintf->device.set_render_state)(m_device, D3DRS_SRCBLEND, blendsrc); |
| 398 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_state call\n", (int)result); |
| 399 | | } |
| 400 | | |
| 401 | | if (blenddst != m_last_blenddst) |
| 402 | | { |
| 403 | | m_last_blenddst = blenddst; |
| 404 | | HRESULT result = (*d3dintf->device.set_render_state)(m_device, D3DRS_DESTBLEND, blenddst); |
| 405 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_state call\n", (int)result); |
| 406 | | } |
| 407 | | } |
| 408 | | |
| 409 | | void renderer::reset_render_states() |
| 410 | | { |
| 411 | | // this ensures subsequent calls to the above setters will force-update the data |
| 412 | | m_last_texture = (texture_info *)~0; |
| 413 | | m_last_filter = -1; |
| 414 | | m_last_blendenable = -1; |
| 415 | | m_last_blendop = -1; |
| 416 | | m_last_blendsrc = -1; |
| 417 | | m_last_blenddst = -1; |
| 418 | | m_last_wrap = (D3DTEXTUREADDRESS)-1; |
| 419 | | } |
| 420 | | |
| 421 | | texture_manager::texture_manager(renderer *d3d) |
| 422 | | { |
| 423 | | m_renderer = d3d; |
| 424 | | |
| 425 | | m_texlist = NULL; |
| 426 | | m_vector_texture = NULL; |
| 427 | | m_default_texture = NULL; |
| 428 | | |
| 429 | | // check for dynamic texture support |
| 430 | | DWORD tempcaps; |
| 431 | | HRESULT result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_CAPS2, &tempcaps); |
| 432 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result); |
| 433 | | m_dynamic_supported = ((tempcaps & D3DCAPS2_DYNAMICTEXTURES) != 0); |
| 434 | | if (m_dynamic_supported) osd_printf_verbose("Direct3D: Using dynamic textures\n"); |
| 435 | | |
| 436 | | // check for stretchrect support |
| 437 | | result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_STRETCH_RECT_FILTER, &tempcaps); |
| 438 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result); |
| 439 | | m_stretch_supported = ((tempcaps & D3DPTFILTERCAPS_MAGFPOINT) != 0); |
| 440 | | if (m_stretch_supported && video_config.prescale > 1) osd_printf_verbose("Direct3D: Using StretchRect for prescaling\n"); |
| 441 | | |
| 442 | | // get texture caps |
| 443 | | result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_TEXTURE_CAPS, &m_texture_caps); |
| 444 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result); |
| 445 | | result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_MAX_TEXTURE_ASPECT, &m_texture_max_aspect); |
| 446 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result); |
| 447 | | result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_MAX_TEXTURE_WIDTH, &m_texture_max_width); |
| 448 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result); |
| 449 | | result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_MAX_TEXTURE_HEIGHT, &m_texture_max_height); |
| 450 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result); |
| 451 | | |
| 452 | | // pick a YUV texture format |
| 453 | | m_yuv_format = D3DFMT_UYVY; |
| 454 | | result = (*d3dintf->d3d.check_device_format)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, d3d->get_pixel_format(), 0, D3DRTYPE_TEXTURE, D3DFMT_UYVY); |
| 455 | | if (result != D3D_OK) |
| 456 | | { |
| 457 | | m_yuv_format = D3DFMT_YUY2; |
| 458 | | result = (*d3dintf->d3d.check_device_format)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, d3d->get_pixel_format(), 0, D3DRTYPE_TEXTURE, D3DFMT_YUY2); |
| 459 | | if (result != D3D_OK) |
| 460 | | m_yuv_format = D3DFMT_A8R8G8B8; |
| 461 | | } |
| 462 | | osd_printf_verbose("Direct3D: YUV format = %s\n", (m_yuv_format == D3DFMT_YUY2) ? "YUY2" : (m_yuv_format == D3DFMT_UYVY) ? "UYVY" : "RGB"); |
| 463 | | |
| 464 | | // set the max texture size |
| 465 | | d3d->window().target()->set_max_texture_size(m_texture_max_width, m_texture_max_height); |
| 466 | | osd_printf_verbose("Direct3D: Max texture size = %dx%d\n", (int)m_texture_max_width, (int)m_texture_max_height); |
| 467 | | } |
| 468 | | |
| 469 | | texture_manager::~texture_manager() |
| 470 | | { |
| 471 | | } |
| 472 | | |
| 473 | | void texture_manager::create_resources() |
| 474 | | { |
| 475 | | // experimental: load a PNG to use for vector rendering; it is treated |
| 476 | | // as a brightness map |
| 477 | | emu_file file(m_renderer->window().machine().options().art_path(), OPEN_FLAG_READ); |
| 478 | | render_load_png(m_vector_bitmap, file, NULL, "vector.png"); |
| 479 | | if (m_vector_bitmap.valid()) |
| 480 | | { |
| 481 | | m_vector_bitmap.fill(rgb_t(0xff,0xff,0xff,0xff)); |
| 482 | | render_load_png(m_vector_bitmap, file, NULL, "vector.png", true); |
| 483 | | } |
| 484 | | |
| 485 | | m_default_bitmap.allocate(8, 8); |
| 486 | | m_default_bitmap.fill(rgb_t(0xff,0xff,0xff,0xff)); |
| 487 | | |
| 488 | | if (m_default_bitmap.valid()) |
| 489 | | { |
| 490 | | render_texinfo texture; |
| 491 | | |
| 492 | | // fake in the basic data so it looks like it came from render.c |
| 493 | | texture.base = m_default_bitmap.raw_pixptr(0); |
| 494 | | texture.rowpixels = m_default_bitmap.rowpixels(); |
| 495 | | texture.width = m_default_bitmap.width(); |
| 496 | | texture.height = m_default_bitmap.height(); |
| 497 | | texture.palette = NULL; |
| 498 | | texture.seqid = 0; |
| 499 | | |
| 500 | | // now create it |
| 501 | | m_default_texture = global_alloc(texture_info(this, &texture, m_renderer->window().prescale(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32))); |
| 502 | | } |
| 503 | | |
| 504 | | // experimental: if we have a vector bitmap, create a texture for it |
| 505 | | if (m_vector_bitmap.valid()) |
| 506 | | { |
| 507 | | render_texinfo texture; |
| 508 | | |
| 509 | | // fake in the basic data so it looks like it came from render.c |
| 510 | | texture.base = &m_vector_bitmap.pix32(0); |
| 511 | | texture.rowpixels = m_vector_bitmap.rowpixels(); |
| 512 | | texture.width = m_vector_bitmap.width(); |
| 513 | | texture.height = m_vector_bitmap.height(); |
| 514 | | texture.palette = NULL; |
| 515 | | texture.seqid = 0; |
| 516 | | |
| 517 | | // now create it |
| 518 | | m_vector_texture = global_alloc(texture_info(this, &texture, m_renderer->window().prescale(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32))); |
| 519 | | } |
| 520 | | } |
| 521 | | |
| 522 | | void texture_manager::delete_resources() |
| 523 | | { |
| 524 | | // is part of m_texlist and will be free'd there |
| 525 | | //global_free(m_default_texture); |
| 526 | | m_default_texture = NULL; |
| 527 | | |
| 528 | | //global_free(m_vector_texture); |
| 529 | | m_vector_texture = NULL; |
| 530 | | |
| 531 | | // free all textures |
| 532 | | while (m_texlist != NULL) |
| 533 | | { |
| 534 | | texture_info *tex = m_texlist; |
| 535 | | m_texlist = tex->get_next(); |
| 536 | | global_free(tex); |
| 537 | | } |
| 538 | | } |
| 539 | | |
| 540 | | UINT32 texture_manager::texture_compute_hash(const render_texinfo *texture, UINT32 flags) |
| 541 | | { |
| 542 | | return (FPTR)texture->base ^ (flags & (PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)); |
| 543 | | } |
| 544 | | |
| 545 | | texture_info *texture_manager::find_texinfo(const render_texinfo *texinfo, UINT32 flags) |
| 546 | | { |
| 547 | | UINT32 hash = texture_compute_hash(texinfo, flags); |
| 548 | | texture_info *texture; |
| 549 | | |
| 550 | | // find a match |
| 551 | | for (texture = m_renderer->get_texture_manager()->get_texlist(); texture != NULL; texture = texture->get_next()) |
| 552 | | { |
| 553 | | UINT32 test_screen = (UINT32)texture->get_texinfo().osddata >> 1; |
| 554 | | UINT32 test_page = (UINT32)texture->get_texinfo().osddata & 1; |
| 555 | | UINT32 prim_screen = (UINT32)texinfo->osddata >> 1; |
| 556 | | UINT32 prim_page = (UINT32)texinfo->osddata & 1; |
| 557 | | if (test_screen != prim_screen || test_page != prim_page) |
| 558 | | { |
| 559 | | continue; |
| 560 | | } |
| 561 | | |
| 562 | | if (texture->get_hash() == hash && |
| 563 | | texture->get_texinfo().base == texinfo->base && |
| 564 | | texture->get_texinfo().width == texinfo->width && |
| 565 | | texture->get_texinfo().height == texinfo->height && |
| 566 | | ((texture->get_flags() ^ flags) & (PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)) == 0) |
| 567 | | { |
| 568 | | // Reject a texture if it belongs to an out-of-date render target, so as to cause the HLSL system to re-cache |
| 569 | | if (m_renderer->get_shaders()->enabled() && texinfo->width != 0 && texinfo->height != 0 && (flags & PRIMFLAG_SCREENTEX_MASK) != 0) |
| 570 | | { |
| 571 | | if (m_renderer->get_shaders()->find_render_target(texture) != NULL) |
| 572 | | { |
| 573 | | return texture; |
| 574 | | } |
| 575 | | } |
| 576 | | else |
| 577 | | { |
| 578 | | return texture; |
| 579 | | } |
| 580 | | } |
| 581 | | } |
| 582 | | |
| 583 | | // Nothing found, check if we need to unregister something with HLSL |
| 584 | | if (m_renderer->get_shaders()->enabled()) |
| 585 | | { |
| 586 | | if (texinfo->width == 0 || texinfo->height == 0) |
| 587 | | { |
| 588 | | return NULL; |
| 589 | | } |
| 590 | | |
| 591 | | UINT32 prim_screen = texinfo->osddata >> 1; |
| 592 | | UINT32 prim_page = texinfo->osddata & 1; |
| 593 | | |
| 594 | | for (texture = m_renderer->get_texture_manager()->get_texlist(); texture != NULL; texture = texture->get_next()) |
| 595 | | { |
| 596 | | UINT32 test_screen = texture->get_texinfo().osddata >> 1; |
| 597 | | UINT32 test_page = texture->get_texinfo().osddata & 1; |
| 598 | | if (test_screen != prim_screen || test_page != prim_page) |
| 599 | | { |
| 600 | | continue; |
| 601 | | } |
| 602 | | |
| 603 | | // Clear out our old texture reference |
| 604 | | if (texture->get_hash() == hash && |
| 605 | | texture->get_texinfo().base == texinfo->base && |
| 606 | | ((texture->get_flags() ^ flags) & (PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)) == 0 && |
| 607 | | (texture->get_texinfo().width != texinfo->width || |
| 608 | | texture->get_texinfo().height != texinfo->height)) |
| 609 | | { |
| 610 | | m_renderer->get_shaders()->remove_render_target(texture); |
| 611 | | } |
| 612 | | } |
| 613 | | } |
| 614 | | |
| 615 | | return NULL; |
| 616 | | } |
| 617 | | |
| 618 | | renderer::renderer(osd_window *window) |
| 619 | | : osd_renderer(window, FLAG_NONE) |
| 620 | | { |
| 621 | | m_device = NULL; |
| 622 | | m_restarting = false; |
| 623 | | m_shaders = NULL; |
| 624 | | m_numverts = 0; |
| 625 | | m_numpolys = 0; |
| 626 | | m_vertexbuf = NULL; |
| 627 | | m_lockedbuf = NULL; |
| 628 | | m_vectorbatch = NULL; |
| 629 | | m_last_texture = NULL; |
| 630 | | m_hlsl_buf = NULL; |
| 631 | | m_texture_manager = NULL; |
| 632 | | } |
| 633 | | |
| 634 | | int renderer::initialize() |
| 635 | | { |
| 636 | | // configure the adapter for the mode we want |
| 637 | | if (config_adapter_mode()) |
| 638 | | return false; |
| 639 | | |
| 640 | | // create the device immediately for the full screen case (defer for window mode) |
| 641 | | if (window().fullscreen() && device_create(window().m_focus_hwnd)) |
| 642 | | return false; |
| 643 | | |
| 644 | | return true; |
| 645 | | } |
| 646 | | |
| 647 | | int renderer::pre_window_draw_check() |
| 648 | | { |
| 649 | | // if we're in the middle of resizing, leave things alone |
| 650 | | if (window().m_resize_state == RESIZE_STATE_RESIZING) |
| 651 | | return 0; |
| 652 | | |
| 653 | | // if we're restarting the renderer, leave things alone |
| 654 | | if (m_restarting) |
| 655 | | { |
| 656 | | m_shaders->toggle(); |
| 657 | | |
| 658 | | // free all existing resources and re-create |
| 659 | | device_delete_resources(); |
| 660 | | device_create_resources(); |
| 661 | | |
| 662 | | m_restarting = false; |
| 663 | | } |
| 664 | | |
| 665 | | // if we have a device, check the cooperative level |
| 666 | | if (m_device != NULL) |
| 667 | | { |
| 668 | | if (device_test_cooperative()) |
| 669 | | { |
| 670 | | return 1; |
| 671 | | } |
| 672 | | } |
| 673 | | |
| 674 | | // in window mode, we need to track the window size |
| 675 | | if (!window().fullscreen() || m_device == NULL) |
| 676 | | { |
| 677 | | // if the size changes, skip this update since the render target will be out of date |
| 678 | | if (update_window_size()) |
| 679 | | return 0; |
| 680 | | |
| 681 | | // if we have no device, after updating the size, return an error so GDI can try |
| 682 | | if (m_device == NULL) |
| 683 | | return 1; |
| 684 | | } |
| 685 | | |
| 686 | | return -1; |
| 687 | | } |
| 688 | | |
| 689 | | void texture_manager::update_textures() |
| 690 | | { |
| 691 | | for (render_primitive *prim = m_renderer->window().m_primlist->first(); prim != NULL; prim = prim->next()) |
| 692 | | { |
| 693 | | if (prim->texture.base != NULL) |
| 694 | | { |
| 695 | | texture_info *texture = find_texinfo(&prim->texture, prim->flags); |
| 696 | | if (texture == NULL) |
| 697 | | { |
| 698 | | // if there isn't one, create a new texture |
| 699 | | global_alloc(texture_info(this, &prim->texture, m_renderer->window().prescale(), prim->flags)); |
| 700 | | } |
| 701 | | else |
| 702 | | { |
| 703 | | // if there is one, but with a different seqid, copy the data |
| 704 | | if (texture->get_texinfo().seqid != prim->texture.seqid) |
| 705 | | { |
| 706 | | texture->set_data(&prim->texture, prim->flags); |
| 707 | | texture->get_texinfo().seqid = prim->texture.seqid; |
| 708 | | } |
| 709 | | } |
| 710 | | } |
| 711 | | else if(m_renderer->get_shaders()->vector_enabled() && PRIMFLAG_GET_VECTORBUF(prim->flags)) |
| 712 | | { |
| 713 | | if (!m_renderer->get_shaders()->get_vector_target()) |
| 714 | | { |
| 715 | | m_renderer->get_shaders()->create_vector_target(prim); |
| 716 | | } |
| 717 | | } |
| 718 | | } |
| 719 | | } |
| 720 | | |
| 721 | | void renderer::begin_frame() |
| 722 | | { |
| 723 | | HRESULT result = (*d3dintf->device.clear)(m_device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); |
| 724 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result); |
| 725 | | |
| 726 | | m_shaders->begin_frame(); |
| 727 | | |
| 728 | | window().m_primlist->acquire_lock(); |
| 729 | | |
| 730 | | // first update any textures |
| 731 | | m_texture_manager->update_textures(); |
| 732 | | |
| 733 | | // begin the scene |
| 734 | | mtlog_add("drawd3d_window_draw: begin_scene"); |
| 735 | | result = (*d3dintf->device.begin_scene)(m_device); |
| 736 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device begin_scene call\n", (int)result); |
| 737 | | |
| 738 | | m_lockedbuf = NULL; |
| 739 | | |
| 740 | | if(m_shaders->enabled()) |
| 741 | | { |
| 742 | | m_hlsl_buf = (void*)mesh_alloc(6); |
| 743 | | m_shaders->init_fsfx_quad(m_hlsl_buf); |
| 744 | | } |
| 745 | | |
| 746 | | m_line_count = 0; |
| 747 | | |
| 748 | | // loop over primitives |
| 749 | | for (render_primitive *prim = window().m_primlist->first(); prim != NULL; prim = prim->next()) |
| 750 | | if (prim->type == render_primitive::LINE && PRIMFLAG_GET_VECTOR(prim->flags)) |
| 751 | | m_line_count++; |
| 752 | | } |
| 753 | | |
| 754 | | void renderer::process_primitives() |
| 755 | | { |
| 756 | | // Rotating index for vector time offsets |
| 757 | | for (render_primitive *prim = window().m_primlist->first(); prim != NULL; prim = prim->next()) |
| 758 | | { |
| 759 | | switch (prim->type) |
| 760 | | { |
| 761 | | case render_primitive::LINE: |
| 762 | | if (PRIMFLAG_GET_VECTOR(prim->flags)) |
| 763 | | { |
| 764 | | if (m_line_count > 0) |
| 765 | | batch_vectors(); |
| 766 | | else |
| 767 | | continue; |
| 768 | | } |
| 769 | | else |
| 770 | | { |
| 771 | | draw_line(prim); |
| 772 | | } |
| 773 | | break; |
| 774 | | |
| 775 | | case render_primitive::QUAD: |
| 776 | | draw_quad(prim); |
| 777 | | break; |
| 778 | | |
| 779 | | default: |
| 780 | | throw emu_fatalerror("Unexpected render_primitive type"); |
| 781 | | } |
| 782 | | } |
| 783 | | } |
| 784 | | |
| 785 | | void renderer::end_frame() |
| 786 | | { |
| 787 | | window().m_primlist->release_lock(); |
| 788 | | |
| 789 | | // flush any pending polygons |
| 790 | | primitive_flush_pending(); |
| 791 | | |
| 792 | | m_shaders->end_frame(); |
| 793 | | |
| 794 | | // finish the scene |
| 795 | | HRESULT result = (*d3dintf->device.end_scene)(m_device); |
| 796 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device end_scene call\n", (int)result); |
| 797 | | |
| 798 | | // present the current buffers |
| 799 | | result = (*d3dintf->device.present)(m_device, NULL, NULL, NULL, NULL, 0); |
| 800 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device present call\n", (int)result); |
| 801 | | } |
| 802 | | |
| 803 | | //============================================================ |
| 804 | | // device_create |
| 805 | | //============================================================ |
| 806 | | |
| 807 | | int renderer::device_create(HWND device_hwnd) |
| 808 | | { |
| 809 | | // if a device exists, free it |
| 810 | | if (m_device != NULL) |
| 811 | | { |
| 812 | | device_delete(); |
| 813 | | } |
| 814 | | |
| 815 | | // create shader options only once |
| 816 | | if (m_shaders_options == NULL) |
| 817 | | { |
| 818 | | m_shaders_options = (hlsl_options*)global_alloc_clear(hlsl_options); |
| 819 | | } |
| 820 | | |
| 821 | | // verify the caps |
| 822 | | int verify = device_verify_caps(); |
| 823 | | if (verify == 2) |
| 824 | | { |
| 825 | | osd_printf_error("Error: Device does not meet minimum requirements for Direct3D rendering\n"); |
| 826 | | return 1; |
| 827 | | } |
| 828 | | if (verify == 1) |
| 829 | | { |
| 830 | | osd_printf_warning("Warning: Device may not perform well for Direct3D rendering\n"); |
| 831 | | } |
| 832 | | |
| 833 | | // verify texture formats |
| 834 | | HRESULT result = (*d3dintf->d3d.check_device_format)(d3dintf, m_adapter, D3DDEVTYPE_HAL, m_pixformat, 0, D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8); |
| 835 | | if (result != D3D_OK) |
| 836 | | { |
| 837 | | osd_printf_error("Error: A8R8G8B8 format textures not supported\n"); |
| 838 | | return 1; |
| 839 | | } |
| 840 | | |
| 841 | | m_texture_manager = global_alloc(texture_manager(this)); |
| 842 | | |
| 843 | | try_again: |
| 844 | | // try for XRGB first |
| 845 | | m_screen_format = D3DFMT_X8R8G8B8; |
| 846 | | result = (*d3dintf->d3d.check_device_format)(d3dintf, m_adapter, D3DDEVTYPE_HAL, m_pixformat, m_texture_manager->is_dynamic_supported() ? D3DUSAGE_DYNAMIC : 0, D3DRTYPE_TEXTURE, m_screen_format); |
| 847 | | if (result != D3D_OK) |
| 848 | | { |
| 849 | | // if not, try for ARGB |
| 850 | | m_screen_format = D3DFMT_A8R8G8B8; |
| 851 | | result = (*d3dintf->d3d.check_device_format)(d3dintf, m_adapter, D3DDEVTYPE_HAL, m_pixformat, m_texture_manager->is_dynamic_supported() ? D3DUSAGE_DYNAMIC : 0, D3DRTYPE_TEXTURE, m_screen_format); |
| 852 | | if (result != D3D_OK && m_texture_manager->is_dynamic_supported()) |
| 853 | | { |
| 854 | | m_texture_manager->set_dynamic_supported(FALSE); |
| 855 | | goto try_again; |
| 856 | | } |
| 857 | | if (result != D3D_OK) |
| 858 | | { |
| 859 | | osd_printf_error("Error: unable to configure a screen texture format\n"); |
| 860 | | return 1; |
| 861 | | } |
| 862 | | } |
| 863 | | |
| 864 | | // initialize the D3D presentation parameters |
| 865 | | memset(&m_presentation, 0, sizeof(m_presentation)); |
| 866 | | m_presentation.BackBufferWidth = m_width; |
| 867 | | m_presentation.BackBufferHeight = m_height; |
| 868 | | m_presentation.BackBufferFormat = m_pixformat; |
| 869 | | m_presentation.BackBufferCount = video_config.triplebuf ? 2 : 1; |
| 870 | | m_presentation.MultiSampleType = D3DMULTISAMPLE_NONE; |
| 871 | | m_presentation.SwapEffect = D3DSWAPEFFECT_DISCARD; |
| 872 | | m_presentation.hDeviceWindow = window().m_hwnd; |
| 873 | | m_presentation.Windowed = !window().fullscreen() || window().win_has_menu(); |
| 874 | | m_presentation.EnableAutoDepthStencil = FALSE; |
| 875 | | m_presentation.AutoDepthStencilFormat = D3DFMT_D16; |
| 876 | | m_presentation.Flags = 0; |
| 877 | | m_presentation.FullScreen_RefreshRateInHz = m_refresh; |
| 878 | | m_presentation.PresentationInterval = ((video_config.triplebuf && window().fullscreen()) || |
| 879 | | video_config.waitvsync || video_config.syncrefresh) ? |
| 880 | | D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE; |
| 881 | | |
| 882 | | // create the D3D device |
| 883 | | result = (*d3dintf->d3d.create_device)(d3dintf, m_adapter, D3DDEVTYPE_HAL, device_hwnd, |
| 884 | | D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &m_presentation, &m_device); |
| 885 | | if (result != D3D_OK) |
| 886 | | { |
| 887 | | // if we got a "DEVICELOST" error, it may be transitory; count it and only fail if |
| 888 | | // we exceed a threshold |
| 889 | | if (result == D3DERR_DEVICELOST) |
| 890 | | { |
| 891 | | m_create_error_count++; |
| 892 | | if (m_create_error_count < 10) |
| 893 | | { |
| 894 | | return 0; |
| 895 | | } |
| 896 | | } |
| 897 | | |
| 898 | | // fatal error if we just can't do it |
| 899 | | osd_printf_error("Unable to create the Direct3D device (%08X)\n", (UINT32)result); |
| 900 | | return 1; |
| 901 | | } |
| 902 | | m_create_error_count = 0; |
| 903 | | osd_printf_verbose("Direct3D: Device created at %dx%d\n", m_width, m_height); |
| 904 | | |
| 905 | | // set the gamma if we need to |
| 906 | | if (window().fullscreen()) |
| 907 | | { |
| 908 | | // only set the gamma if it's not 1.0f |
| 909 | | windows_options &options = downcast<windows_options &>(window().machine().options()); |
| 910 | | float brightness = options.full_screen_brightness(); |
| 911 | | float contrast = options.full_screen_contrast(); |
| 912 | | float gamma = options.full_screen_gamma(); |
| 913 | | if (brightness != 1.0f || contrast != 1.0f || gamma != 1.0f) |
| 914 | | { |
| 915 | | // warn if we can't do it |
| 916 | | if (!m_gamma_supported) |
| 917 | | { |
| 918 | | osd_printf_warning("Direct3D: Warning - device does not support full screen gamma correction.\n"); |
| 919 | | } |
| 920 | | else |
| 921 | | { |
| 922 | | // create a standard ramp and set it |
| 923 | | D3DGAMMARAMP ramp; |
| 924 | | for (int i = 0; i < 256; i++) |
| 925 | | { |
| 926 | | ramp.red[i] = ramp.green[i] = ramp.blue[i] = apply_brightness_contrast_gamma(i, brightness, contrast, gamma) << 8; |
| 927 | | } |
| 928 | | (*d3dintf->device.set_gamma_ramp)(m_device, 0, &ramp); |
| 929 | | } |
| 930 | | } |
| 931 | | } |
| 932 | | |
| 933 | | int ret = m_shaders->create_resources(false); |
| 934 | | if (ret != 0) |
| 935 | | return ret; |
| 936 | | |
| 937 | | return device_create_resources(); |
| 938 | | } |
| 939 | | |
| 940 | | |
| 941 | | //============================================================ |
| 942 | | // device_create_resources |
| 943 | | //============================================================ |
| 944 | | |
| 945 | | int renderer::device_create_resources() |
| 946 | | { |
| 947 | | // allocate a vertex buffer to use |
| 948 | | HRESULT result = (*d3dintf->device.create_vertex_buffer)(m_device, |
| 949 | | sizeof(vertex) * VERTEX_BUFFER_SIZE, |
| 950 | | D3DUSAGE_DYNAMIC | D3DUSAGE_SOFTWAREPROCESSING | D3DUSAGE_WRITEONLY, |
| 951 | | VERTEX_BASE_FORMAT | ((m_shaders->enabled() && d3dintf->post_fx_available) ? D3DFVF_XYZW : D3DFVF_XYZRHW), |
| 952 | | D3DPOOL_DEFAULT, &m_vertexbuf); |
| 953 | | if (result != D3D_OK) |
| 954 | | { |
| 955 | | osd_printf_error("Error creating vertex buffer (%08X)\n", (UINT32)result); |
| 956 | | return 1; |
| 957 | | } |
| 958 | | |
| 959 | | // set the vertex format |
| 960 | | result = (*d3dintf->device.set_vertex_format)(m_device, (D3DFORMAT)(VERTEX_BASE_FORMAT | ((m_shaders->enabled() && |
| 961 | | d3dintf->post_fx_available) ? D3DFVF_XYZW : D3DFVF_XYZRHW))); |
| 962 | | if (result != D3D_OK) |
| 963 | | { |
| 964 | | osd_printf_error("Error setting vertex format (%08X)\n", (UINT32)result); |
| 965 | | return 1; |
| 966 | | } |
| 967 | | |
| 968 | | // set the fixed render state |
| 969 | | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ZENABLE, D3DZB_FALSE); |
| 970 | | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_FILLMODE, D3DFILL_SOLID); |
| 971 | | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_SHADEMODE, D3DSHADE_FLAT); |
| 972 | | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ZWRITEENABLE, FALSE); |
| 973 | | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ALPHATESTENABLE, TRUE); |
| 974 | | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_LASTPIXEL, TRUE); |
| 975 | | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_CULLMODE, D3DCULL_NONE); |
| 976 | | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ZFUNC, D3DCMP_LESS); |
| 977 | | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ALPHAREF, 0); |
| 978 | | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ALPHAFUNC, D3DCMP_GREATER); |
| 979 | | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_DITHERENABLE, FALSE); |
| 980 | | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_FOGENABLE, FALSE); |
| 981 | | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_SPECULARENABLE, FALSE); |
| 982 | | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_STENCILENABLE, FALSE); |
| 983 | | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_WRAP0, FALSE); |
| 984 | | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_CLIPPING, TRUE); |
| 985 | | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_LIGHTING, FALSE); |
| 986 | | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_COLORVERTEX, TRUE); |
| 987 | | |
| 988 | | result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, D3DTSS_COLOROP, D3DTOP_MODULATE); |
| 989 | | result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); |
| 990 | | result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, D3DTSS_COLOROP, D3DTOP_MODULATE); |
| 991 | | result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, D3DTSS_ALPHAOP, D3DTOP_MODULATE); |
| 992 | | |
| 993 | | // reset the local states to force updates |
| 994 | | reset_render_states(); |
| 995 | | |
| 996 | | // clear the buffer |
| 997 | | result = (*d3dintf->device.clear)(m_device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); |
| 998 | | result = (*d3dintf->device.present)(m_device, NULL, NULL, NULL, NULL, 0); |
| 999 | | |
| 1000 | | m_texture_manager->create_resources(); |
| 1001 | | |
| 1002 | | return 0; |
| 1003 | | } |
| 1004 | | |
| 1005 | | |
| 1006 | | //============================================================ |
| 1007 | | // device_delete |
| 1008 | | //============================================================ |
| 1009 | | |
| 1010 | | renderer::~renderer() |
| 1011 | | { |
| 1012 | | if (m_shaders_options != NULL) |
| 1013 | | { |
| 1014 | | global_free(m_shaders_options); |
| 1015 | | } |
| 1016 | | m_shaders_options = NULL; |
| 1017 | | |
| 1018 | | device_delete(); |
| 1019 | | } |
| 1020 | | |
| 1021 | | void renderer::device_delete() |
| 1022 | | { |
| 1023 | | if (m_shaders != NULL) |
| 1024 | | { |
| 1025 | | // free our effects |
| 1026 | | m_shaders->delete_resources(false); |
| 1027 | | |
| 1028 | | // delete the HLSL interface |
| 1029 | | global_free(m_shaders); |
| 1030 | | } |
| 1031 | | |
| 1032 | | // free our base resources |
| 1033 | | device_delete_resources(); |
| 1034 | | |
| 1035 | | if (m_texture_manager != NULL) |
| 1036 | | { |
| 1037 | | global_free(m_texture_manager); |
| 1038 | | } |
| 1039 | | m_texture_manager = NULL; |
| 1040 | | |
| 1041 | | // free the device itself |
| 1042 | | if (m_device != NULL) |
| 1043 | | { |
| 1044 | | (*d3dintf->device.reset)(m_device, &m_presentation); |
| 1045 | | (*d3dintf->device.release)(m_device); |
| 1046 | | } |
| 1047 | | m_device = NULL; |
| 1048 | | } |
| 1049 | | |
| 1050 | | |
| 1051 | | //============================================================ |
| 1052 | | // device_delete_resources |
| 1053 | | //============================================================ |
| 1054 | | |
| 1055 | | void renderer::device_delete_resources() |
| 1056 | | { |
| 1057 | | if (m_texture_manager != NULL) |
| 1058 | | m_texture_manager->delete_resources(); |
| 1059 | | // free the vertex buffer |
| 1060 | | if (m_vertexbuf != NULL) |
| 1061 | | (*d3dintf->vertexbuf.release)(m_vertexbuf); |
| 1062 | | m_vertexbuf = NULL; |
| 1063 | | } |
| 1064 | | |
| 1065 | | |
| 1066 | | //============================================================ |
| 1067 | | // device_verify_caps |
| 1068 | | //============================================================ |
| 1069 | | |
| 1070 | | int renderer::device_verify_caps() |
| 1071 | | { |
| 1072 | | int retval = 0; |
| 1073 | | |
| 1074 | | m_shaders = (shaders*)global_alloc_clear(shaders); |
| 1075 | | m_shaders->init(d3dintf, &window().machine(), this); |
| 1076 | | |
| 1077 | | DWORD tempcaps; |
| 1078 | | HRESULT result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_MAX_PS30_INSN_SLOTS, &tempcaps); |
| 1079 | | if (result != D3D_OK) osd_printf_verbose("Direct3D Error %08X during get_caps_dword call\n", (int)result); |
| 1080 | | if (tempcaps < 512) |
| 1081 | | { |
| 1082 | | osd_printf_verbose("Direct3D: Warning - Device does not support Pixel Shader 3.0, falling back to non-PS rendering\n"); |
| 1083 | | d3dintf->post_fx_available = false; |
| 1084 | | } |
| 1085 | | |
| 1086 | | // verify presentation capabilities |
| 1087 | | result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_PRESENTATION_INTERVALS, &tempcaps); |
| 1088 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result); |
| 1089 | | if (!(tempcaps & D3DPRESENT_INTERVAL_IMMEDIATE)) |
| 1090 | | { |
| 1091 | | osd_printf_verbose("Direct3D: Error - Device does not support immediate presentations\n"); |
| 1092 | | retval = 2; |
| 1093 | | } |
| 1094 | | if (!(tempcaps & D3DPRESENT_INTERVAL_ONE)) |
| 1095 | | { |
| 1096 | | osd_printf_verbose("Direct3D: Error - Device does not support per-refresh presentations\n"); |
| 1097 | | retval = 2; |
| 1098 | | } |
| 1099 | | |
| 1100 | | // verify device capabilities |
| 1101 | | result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_DEV_CAPS, &tempcaps); |
| 1102 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result); |
| 1103 | | if (!(tempcaps & D3DDEVCAPS_CANRENDERAFTERFLIP)) |
| 1104 | | { |
| 1105 | | osd_printf_verbose("Direct3D: Warning - Device does not support queued rendering after a page flip\n"); |
| 1106 | | retval = 1; |
| 1107 | | } |
| 1108 | | if (!(tempcaps & D3DDEVCAPS_HWRASTERIZATION)) |
| 1109 | | { |
| 1110 | | osd_printf_verbose("Direct3D: Warning - Device does not support hardware rasterization\n"); |
| 1111 | | retval = 1; |
| 1112 | | } |
| 1113 | | |
| 1114 | | // verify texture operation capabilities |
| 1115 | | result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_TEXTURE_OP_CAPS, &tempcaps); |
| 1116 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result); |
| 1117 | | if (!(tempcaps & D3DTEXOPCAPS_MODULATE)) |
| 1118 | | { |
| 1119 | | osd_printf_verbose("Direct3D: Warning - Device does not support texture modulation\n"); |
| 1120 | | retval = 1; |
| 1121 | | } |
| 1122 | | |
| 1123 | | // set a simpler flag to indicate mod2x and mod4x texture modes |
| 1124 | | m_mod2x_supported = ((tempcaps & D3DTEXOPCAPS_MODULATE2X) != 0); |
| 1125 | | m_mod4x_supported = ((tempcaps & D3DTEXOPCAPS_MODULATE4X) != 0); |
| 1126 | | |
| 1127 | | result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_CAPS2, &tempcaps); |
| 1128 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result); |
| 1129 | | m_gamma_supported = ((tempcaps & D3DCAPS2_FULLSCREENGAMMA) != 0); |
| 1130 | | |
| 1131 | | return retval; |
| 1132 | | } |
| 1133 | | |
| 1134 | | |
| 1135 | | //============================================================ |
| 1136 | | // device_test_cooperative |
| 1137 | | //============================================================ |
| 1138 | | |
| 1139 | | int renderer::device_test_cooperative() |
| 1140 | | { |
| 1141 | | // check our current status; if we lost the device, punt to GDI |
| 1142 | | HRESULT result = (*d3dintf->device.test_cooperative_level)(m_device); |
| 1143 | | if (result == D3DERR_DEVICELOST) |
| 1144 | | return 1; |
| 1145 | | |
| 1146 | | // if we're able to reset ourselves, try it |
| 1147 | | if (result == D3DERR_DEVICENOTRESET) |
| 1148 | | { |
| 1149 | | osd_printf_verbose("Direct3D: resetting device\n"); |
| 1150 | | |
| 1151 | | // free all existing resources and call reset on the device |
| 1152 | | //device_delete(); |
| 1153 | | device_delete_resources(); |
| 1154 | | m_shaders->delete_resources(true); |
| 1155 | | result = (*d3dintf->device.reset)(m_device, &m_presentation); |
| 1156 | | |
| 1157 | | // if it didn't work, punt to GDI |
| 1158 | | if (result != D3D_OK) |
| 1159 | | { |
| 1160 | | osd_printf_error("Unable to reset, result %08x\n", (UINT32)result); |
| 1161 | | return 1; |
| 1162 | | } |
| 1163 | | |
| 1164 | | // try to create the resources again; if that didn't work, delete the whole thing |
| 1165 | | if (device_create_resources()) |
| 1166 | | { |
| 1167 | | osd_printf_verbose("Direct3D: failed to recreate resources for device; failing permanently\n"); |
| 1168 | | device_delete(); |
| 1169 | | return 1; |
| 1170 | | } |
| 1171 | | |
| 1172 | | if (m_shaders->create_resources(true)) |
| 1173 | | { |
| 1174 | | osd_printf_verbose("Direct3D: failed to recreate HLSL resources for device; failing permanently\n"); |
| 1175 | | device_delete(); |
| 1176 | | return 1; |
| 1177 | | } |
| 1178 | | } |
| 1179 | | return 0; |
| 1180 | | } |
| 1181 | | |
| 1182 | | |
| 1183 | | //============================================================ |
| 1184 | | // config_adapter_mode |
| 1185 | | //============================================================ |
| 1186 | | |
| 1187 | | int renderer::config_adapter_mode() |
| 1188 | | { |
| 1189 | | adapter_identifier identifier; |
| 1190 | | |
| 1191 | | // choose the monitor number |
| 1192 | | m_adapter = get_adapter_for_monitor(); |
| 1193 | | |
| 1194 | | // get the identifier |
| 1195 | | HRESULT result = (*d3dintf->d3d.get_adapter_identifier)(d3dintf, m_adapter, 0, &identifier); |
| 1196 | | if (result != D3D_OK) |
| 1197 | | { |
| 1198 | | osd_printf_error("Error getting identifier for adapter #%d\n", m_adapter); |
| 1199 | | return 1; |
| 1200 | | } |
| 1201 | | osd_printf_verbose("Direct3D: Configuring adapter #%d = %s\n", m_adapter, identifier.Description); |
| 1202 | | |
| 1203 | | // get the current display mode |
| 1204 | | result = (*d3dintf->d3d.get_adapter_display_mode)(d3dintf, m_adapter, &m_origmode); |
| 1205 | | if (result != D3D_OK) |
| 1206 | | { |
| 1207 | | osd_printf_error("Error getting mode for adapter #%d\n", m_adapter); |
| 1208 | | return 1; |
| 1209 | | } |
| 1210 | | |
| 1211 | | // choose a resolution: window mode case |
| 1212 | | if (!window().fullscreen() || !video_config.switchres || window().win_has_menu()) |
| 1213 | | { |
| 1214 | | RECT client; |
| 1215 | | |
| 1216 | | // bounds are from the window client rect |
| 1217 | | GetClientRectExceptMenu(window().m_hwnd, &client, window().fullscreen()); |
| 1218 | | m_width = client.right - client.left; |
| 1219 | | m_height = client.bottom - client.top; |
| 1220 | | |
| 1221 | | // pix format is from the current mode |
| 1222 | | m_pixformat = m_origmode.Format; |
| 1223 | | m_refresh = 0; |
| 1224 | | |
| 1225 | | // make sure it's a pixel format we can get behind |
| 1226 | | if (m_pixformat != D3DFMT_X1R5G5B5 && m_pixformat != D3DFMT_R5G6B5 && m_pixformat != D3DFMT_X8R8G8B8) |
| 1227 | | { |
| 1228 | | osd_printf_error("Device %s currently in an unsupported mode\n", window().monitor()->devicename()); |
| 1229 | | return 1; |
| 1230 | | } |
| 1231 | | } |
| 1232 | | |
| 1233 | | // choose a resolution: full screen mode case |
| 1234 | | else |
| 1235 | | { |
| 1236 | | // default to the current mode exactly |
| 1237 | | m_width = m_origmode.Width; |
| 1238 | | m_height = m_origmode.Height; |
| 1239 | | m_pixformat = m_origmode.Format; |
| 1240 | | m_refresh = m_origmode.RefreshRate; |
| 1241 | | |
| 1242 | | // if we're allowed to switch resolutions, override with something better |
| 1243 | | if (video_config.switchres) |
| 1244 | | pick_best_mode(); |
| 1245 | | } |
| 1246 | | |
| 1247 | | // see if we can handle the device type |
| 1248 | | result = (*d3dintf->d3d.check_device_type)(d3dintf, m_adapter, D3DDEVTYPE_HAL, m_pixformat, m_pixformat, !window().fullscreen()); |
| 1249 | | if (result != D3D_OK) |
| 1250 | | { |
| 1251 | | osd_printf_error("Proposed video mode not supported on device %s\n", window().monitor()->devicename()); |
| 1252 | | return 1; |
| 1253 | | } |
| 1254 | | return 0; |
| 1255 | | } |
| 1256 | | |
| 1257 | | |
| 1258 | | //============================================================ |
| 1259 | | // get_adapter_for_monitor |
| 1260 | | //============================================================ |
| 1261 | | |
| 1262 | | int renderer::get_adapter_for_monitor() |
| 1263 | | { |
| 1264 | | int maxadapter = (*d3dintf->d3d.get_adapter_count)(d3dintf); |
| 1265 | | |
| 1266 | | // iterate over adapters until we error or find a match |
| 1267 | | for (int adapternum = 0; adapternum < maxadapter; adapternum++) |
| 1268 | | { |
| 1269 | | // get the monitor for this adapter |
| 1270 | | HMONITOR curmonitor = (*d3dintf->d3d.get_adapter_monitor)(d3dintf, adapternum); |
| 1271 | | |
| 1272 | | // if we match the proposed monitor, this is it |
| 1273 | | if (curmonitor == *((HMONITOR *)window().monitor()->oshandle())) |
| 1274 | | { |
| 1275 | | return adapternum; |
| 1276 | | } |
| 1277 | | } |
| 1278 | | |
| 1279 | | // default to the default |
| 1280 | | return D3DADAPTER_DEFAULT; |
| 1281 | | } |
| 1282 | | |
| 1283 | | |
| 1284 | | //============================================================ |
| 1285 | | // pick_best_mode |
| 1286 | | //============================================================ |
| 1287 | | |
| 1288 | | void renderer::pick_best_mode() |
| 1289 | | { |
| 1290 | | double target_refresh = 60.0; |
| 1291 | | INT32 minwidth, minheight; |
| 1292 | | float best_score = 0.0f; |
| 1293 | | |
| 1294 | | // determine the refresh rate of the primary screen |
| 1295 | | const screen_device *primary_screen = window().machine().config().first_screen(); |
| 1296 | | if (primary_screen != NULL) |
| 1297 | | { |
| 1298 | | target_refresh = ATTOSECONDS_TO_HZ(primary_screen->refresh_attoseconds()); |
| 1299 | | } |
| 1300 | | |
| 1301 | | // determine the minimum width/height for the selected target |
| 1302 | | // note: technically we should not be calling this from an alternate window |
| 1303 | | // thread; however, it is only done during init time, and the init code on |
| 1304 | | // the main thread is waiting for us to finish, so it is safe to do so here |
| 1305 | | window().target()->compute_minimum_size(minwidth, minheight); |
| 1306 | | |
| 1307 | | // use those as the target for now |
| 1308 | | INT32 target_width = minwidth; |
| 1309 | | INT32 target_height = minheight; |
| 1310 | | |
| 1311 | | // determine the maximum number of modes |
| 1312 | | int maxmodes = (*d3dintf->d3d.get_adapter_mode_count)(d3dintf, m_adapter, D3DFMT_X8R8G8B8); |
| 1313 | | |
| 1314 | | // enumerate all the video modes and find the best match |
| 1315 | | osd_printf_verbose("Direct3D: Selecting video mode...\n"); |
| 1316 | | for (int modenum = 0; modenum < maxmodes; modenum++) |
| 1317 | | { |
| 1318 | | // check this mode |
| 1319 | | D3DDISPLAYMODE mode; |
| 1320 | | HRESULT result = (*d3dintf->d3d.enum_adapter_modes)(d3dintf, m_adapter, D3DFMT_X8R8G8B8, modenum, &mode); |
| 1321 | | if (result != D3D_OK) |
| 1322 | | break; |
| 1323 | | |
| 1324 | | // skip non-32 bit modes |
| 1325 | | if (mode.Format != D3DFMT_X8R8G8B8) |
| 1326 | | continue; |
| 1327 | | |
| 1328 | | // compute initial score based on difference between target and current |
| 1329 | | float size_score = 1.0f / (1.0f + fabs((float)(mode.Width - target_width)) + fabs((float)(mode.Height - target_height))); |
| 1330 | | |
| 1331 | | // if the mode is too small, give a big penalty |
| 1332 | | if (mode.Width < minwidth || mode.Height < minheight) |
| 1333 | | size_score *= 0.01f; |
| 1334 | | |
| 1335 | | // if mode is smaller than we'd like, it only scores up to 0.1 |
| 1336 | | if (mode.Width < target_width || mode.Height < target_height) |
| 1337 | | size_score *= 0.1f; |
| 1338 | | |
| 1339 | | // if we're looking for a particular mode, that's a winner |
| 1340 | | if (mode.Width == window().m_win_config.width && mode.Height == window().m_win_config.height) |
| 1341 | | size_score = 2.0f; |
| 1342 | | |
| 1343 | | // compute refresh score |
| 1344 | | float refresh_score = 1.0f / (1.0f + fabs((double)mode.RefreshRate - target_refresh)); |
| 1345 | | |
| 1346 | | // if refresh is smaller than we'd like, it only scores up to 0.1 |
| 1347 | | if ((double)mode.RefreshRate < target_refresh) |
| 1348 | | refresh_score *= 0.1f; |
| 1349 | | |
| 1350 | | // if we're looking for a particular refresh, make sure it matches |
| 1351 | | if (mode.RefreshRate == window().m_win_config.refresh) |
| 1352 | | refresh_score = 2.0f; |
| 1353 | | |
| 1354 | | // weight size and refresh equally |
| 1355 | | float final_score = size_score + refresh_score; |
| 1356 | | |
| 1357 | | // best so far? |
| 1358 | | osd_printf_verbose(" %4dx%4d@%3dHz -> %f\n", mode.Width, mode.Height, mode.RefreshRate, final_score * 1000.0f); |
| 1359 | | if (final_score > best_score) |
| 1360 | | { |
| 1361 | | best_score = final_score; |
| 1362 | | m_width = mode.Width; |
| 1363 | | m_height = mode.Height; |
| 1364 | | m_pixformat = mode.Format; |
| 1365 | | m_refresh = mode.RefreshRate; |
| 1366 | | } |
| 1367 | | } |
| 1368 | | osd_printf_verbose("Direct3D: Mode selected = %4dx%4d@%3dHz\n", m_width, m_height, m_refresh); |
| 1369 | | } |
| 1370 | | |
| 1371 | | |
| 1372 | | //============================================================ |
| 1373 | | // update_window_size |
| 1374 | | //============================================================ |
| 1375 | | |
| 1376 | | int renderer::update_window_size() |
| 1377 | | { |
| 1378 | | // get the current window bounds |
| 1379 | | RECT client; |
| 1380 | | GetClientRectExceptMenu(window().m_hwnd, &client, window().fullscreen()); |
| 1381 | | |
| 1382 | | // if we have a device and matching width/height, nothing to do |
| 1383 | | if (m_device != NULL && rect_width(&client) == m_width && rect_height(&client) == m_height) |
| 1384 | | { |
| 1385 | | // clear out any pending resizing if the area didn't change |
| 1386 | | if (window().m_resize_state == RESIZE_STATE_PENDING) |
| 1387 | | window().m_resize_state = RESIZE_STATE_NORMAL; |
| 1388 | | return FALSE; |
| 1389 | | } |
| 1390 | | |
| 1391 | | // if we're in the middle of resizing, leave it alone as well |
| 1392 | | if (window().m_resize_state == RESIZE_STATE_RESIZING) |
| 1393 | | return FALSE; |
| 1394 | | |
| 1395 | | // set the new bounds and create the device again |
| 1396 | | m_width = rect_width(&client); |
| 1397 | | m_height = rect_height(&client); |
| 1398 | | if (device_create(window().m_focus_hwnd)) |
| 1399 | | return FALSE; |
| 1400 | | |
| 1401 | | // reset the resize state to normal, and indicate we made a change |
| 1402 | | window().m_resize_state = RESIZE_STATE_NORMAL; |
| 1403 | | return TRUE; |
| 1404 | | } |
| 1405 | | |
| 1406 | | |
| 1407 | | //============================================================ |
| 1408 | | // batch_vectors |
| 1409 | | //============================================================ |
| 1410 | | |
| 1411 | | void renderer::batch_vectors() |
| 1412 | | { |
| 1413 | | windows_options &options = downcast<windows_options &>(window().machine().options()); |
| 1414 | | |
| 1415 | | int vector_size = (options.antialias() ? 24 : 6); |
| 1416 | | m_vectorbatch = mesh_alloc(m_line_count * vector_size); |
| 1417 | | m_batchindex = 0; |
| 1418 | | |
| 1419 | | static int start_index = 0; |
| 1420 | | int line_index = 0; |
| 1421 | | float period = options.screen_vector_time_period(); |
| 1422 | | UINT32 cached_flags = 0; |
| 1423 | | for (render_primitive *prim = window().m_primlist->first(); prim != NULL; prim = prim->next()) |
| 1424 | | { |
| 1425 | | switch (prim->type) |
| 1426 | | { |
| 1427 | | case render_primitive::LINE: |
| 1428 | | if (PRIMFLAG_GET_VECTOR(prim->flags)) |
| 1429 | | { |
| 1430 | | if (period == 0.0f || m_line_count == 0) |
| 1431 | | { |
| 1432 | | batch_vector(prim, 1.0f); |
| 1433 | | } |
| 1434 | | else |
| 1435 | | { |
| 1436 | | batch_vector(prim, (float)(start_index + line_index) / ((float)m_line_count * period)); |
| 1437 | | line_index++; |
| 1438 | | } |
| 1439 | | cached_flags = prim->flags; |
| 1440 | | } |
| 1441 | | break; |
| 1442 | | |
| 1443 | | default: |
| 1444 | | // Skip |
| 1445 | | break; |
| 1446 | | } |
| 1447 | | } |
| 1448 | | |
| 1449 | | // now add a polygon entry |
| 1450 | | m_poly[m_numpolys].init(D3DPT_TRIANGLELIST, m_line_count * (options.antialias() ? 8 : 2), vector_size * m_line_count, cached_flags, |
| 1451 | | m_texture_manager->get_vector_texture(), D3DTOP_MODULATE, 0.0f, 1.0f, 0.0f, 0.0f); |
| 1452 | | m_numpolys++; |
| 1453 | | |
| 1454 | | start_index += (int)((float)line_index * period); |
| 1455 | | if (m_line_count > 0) |
| 1456 | | { |
| 1457 | | start_index %= m_line_count; |
| 1458 | | } |
| 1459 | | |
| 1460 | | m_line_count = 0; |
| 1461 | | } |
| 1462 | | |
| 1463 | | void renderer::batch_vector(const render_primitive *prim, float line_time) |
| 1464 | | { |
| 1465 | | // compute the effective width based on the direction of the line |
| 1466 | | float effwidth = prim->width; |
| 1467 | | if (effwidth < 0.5f) |
| 1468 | | { |
| 1469 | | effwidth = 0.5f; |
| 1470 | | } |
| 1471 | | |
| 1472 | | // determine the bounds of a quad to draw this line |
| 1473 | | render_bounds b0, b1; |
| 1474 | | render_line_to_quad(&prim->bounds, effwidth, &b0, &b1); |
| 1475 | | |
| 1476 | | // iterate over AA steps |
| 1477 | | for (const line_aa_step *step = PRIMFLAG_GET_ANTIALIAS(prim->flags) ? line_aa_4step : line_aa_1step; |
| 1478 | | step->weight != 0; step++) |
| 1479 | | { |
| 1480 | | // get a pointer to the vertex buffer |
| 1481 | | if (m_vectorbatch == NULL) |
| 1482 | | return; |
| 1483 | | |
| 1484 | | m_vectorbatch[m_batchindex + 0].x = b0.x0 + step->xoffs; |
| 1485 | | m_vectorbatch[m_batchindex + 0].y = b0.y0 + step->yoffs; |
| 1486 | | m_vectorbatch[m_batchindex + 1].x = b0.x1 + step->xoffs; |
| 1487 | | m_vectorbatch[m_batchindex + 1].y = b0.y1 + step->yoffs; |
| 1488 | | m_vectorbatch[m_batchindex + 2].x = b1.x0 + step->xoffs; |
| 1489 | | m_vectorbatch[m_batchindex + 2].y = b1.y0 + step->yoffs; |
| 1490 | | |
| 1491 | | m_vectorbatch[m_batchindex + 3].x = b0.x1 + step->xoffs; |
| 1492 | | m_vectorbatch[m_batchindex + 3].y = b0.y1 + step->yoffs; |
| 1493 | | m_vectorbatch[m_batchindex + 4].x = b1.x0 + step->xoffs; |
| 1494 | | m_vectorbatch[m_batchindex + 4].y = b1.y0 + step->yoffs; |
| 1495 | | m_vectorbatch[m_batchindex + 5].x = b1.x1 + step->xoffs; |
| 1496 | | m_vectorbatch[m_batchindex + 5].y = b1.y1 + step->yoffs; |
| 1497 | | |
| 1498 | | float dx = b1.x1 - b0.x1; |
| 1499 | | float dy = b1.y1 - b0.y1; |
| 1500 | | float line_length = sqrtf(dx * dx + dy * dy); |
| 1501 | | |
| 1502 | | // determine the color of the line |
| 1503 | | INT32 r = (INT32)(prim->color.r * step->weight * 255.0f); |
| 1504 | | INT32 g = (INT32)(prim->color.g * step->weight * 255.0f); |
| 1505 | | INT32 b = (INT32)(prim->color.b * step->weight * 255.0f); |
| 1506 | | INT32 a = (INT32)(prim->color.a * 255.0f); |
| 1507 | | if (r > 255 || g > 255 || b > 255) |
| 1508 | | { |
| 1509 | | if (r > 2*255 || g > 2*255 || b > 2*255) |
| 1510 | | { |
| 1511 | | r >>= 2; g >>= 2; b >>= 2; |
| 1512 | | } |
| 1513 | | else |
| 1514 | | { |
| 1515 | | r >>= 1; g >>= 1; b >>= 1; |
| 1516 | | } |
| 1517 | | } |
| 1518 | | if (r > 255) r = 255; |
| 1519 | | if (g > 255) g = 255; |
| 1520 | | if (b > 255) b = 255; |
| 1521 | | if (a > 255) a = 255; |
| 1522 | | DWORD color = D3DCOLOR_ARGB(a, r, g, b); |
| 1523 | | |
| 1524 | | vec2f& start = (get_vector_texture() ? get_vector_texture()->get_uvstart() : get_default_texture()->get_uvstart()); |
| 1525 | | vec2f& stop = (get_vector_texture() ? get_vector_texture()->get_uvstop() : get_default_texture()->get_uvstop()); |
| 1526 | | |
| 1527 | | m_vectorbatch[m_batchindex + 0].u0 = start.c.x; |
| 1528 | | m_vectorbatch[m_batchindex + 0].v0 = start.c.y; |
| 1529 | | m_vectorbatch[m_batchindex + 1].u0 = start.c.x; |
| 1530 | | m_vectorbatch[m_batchindex + 1].v0 = stop.c.y; |
| 1531 | | m_vectorbatch[m_batchindex + 2].u0 = stop.c.x; |
| 1532 | | m_vectorbatch[m_batchindex + 2].v0 = start.c.y; |
| 1533 | | |
| 1534 | | m_vectorbatch[m_batchindex + 3].u0 = start.c.x; |
| 1535 | | m_vectorbatch[m_batchindex + 3].v0 = stop.c.y; |
| 1536 | | m_vectorbatch[m_batchindex + 4].u0 = stop.c.x; |
| 1537 | | m_vectorbatch[m_batchindex + 4].v0 = start.c.y; |
| 1538 | | m_vectorbatch[m_batchindex + 5].u0 = stop.c.x; |
| 1539 | | m_vectorbatch[m_batchindex + 5].v0 = stop.c.y; |
| 1540 | | |
| 1541 | | m_vectorbatch[m_batchindex + 0].u1 = line_length; |
| 1542 | | m_vectorbatch[m_batchindex + 1].u1 = line_length; |
| 1543 | | m_vectorbatch[m_batchindex + 2].u1 = line_length; |
| 1544 | | m_vectorbatch[m_batchindex + 3].u1 = line_length; |
| 1545 | | m_vectorbatch[m_batchindex + 4].u1 = line_length; |
| 1546 | | m_vectorbatch[m_batchindex + 5].u1 = line_length; |
| 1547 | | |
| 1548 | | // set the color, Z parameters to standard values |
| 1549 | | for (int i = 0; i < 6; i++) |
| 1550 | | { |
| 1551 | | m_vectorbatch[m_batchindex + i].z = 0.0f; |
| 1552 | | m_vectorbatch[m_batchindex + i].rhw = 1.0f; |
| 1553 | | m_vectorbatch[m_batchindex + i].color = color; |
| 1554 | | } |
| 1555 | | |
| 1556 | | m_batchindex += 6; |
| 1557 | | } |
| 1558 | | } |
| 1559 | | |
| 1560 | | |
| 1561 | | //============================================================ |
| 1562 | | // draw_line |
| 1563 | | //============================================================ |
| 1564 | | |
| 1565 | | void renderer::draw_line(const render_primitive *prim) |
| 1566 | | { |
| 1567 | | // compute the effective width based on the direction of the line |
| 1568 | | float effwidth = prim->width; |
| 1569 | | if (effwidth < 0.5f) |
| 1570 | | { |
| 1571 | | effwidth = 0.5f; |
| 1572 | | } |
| 1573 | | |
| 1574 | | // determine the bounds of a quad to draw this line |
| 1575 | | render_bounds b0, b1; |
| 1576 | | render_line_to_quad(&prim->bounds, effwidth, &b0, &b1); |
| 1577 | | |
| 1578 | | // iterate over AA steps |
| 1579 | | for (const line_aa_step *step = PRIMFLAG_GET_ANTIALIAS(prim->flags) ? line_aa_4step : line_aa_1step; |
| 1580 | | step->weight != 0; step++) |
| 1581 | | { |
| 1582 | | // get a pointer to the vertex buffer |
| 1583 | | vertex *vertex = mesh_alloc(4); |
| 1584 | | if (vertex == NULL) |
| 1585 | | return; |
| 1586 | | |
| 1587 | | // rotate the unit vector by 135 degrees and add to point 0 |
| 1588 | | vertex[0].x = b0.x0 + step->xoffs; |
| 1589 | | vertex[0].y = b0.y0 + step->yoffs; |
| 1590 | | |
| 1591 | | // rotate the unit vector by -135 degrees and add to point 0 |
| 1592 | | vertex[1].x = b0.x1 + step->xoffs; |
| 1593 | | vertex[1].y = b0.y1 + step->yoffs; |
| 1594 | | |
| 1595 | | // rotate the unit vector by 45 degrees and add to point 1 |
| 1596 | | vertex[2].x = b1.x0 + step->xoffs; |
| 1597 | | vertex[2].y = b1.y0 + step->yoffs; |
| 1598 | | |
| 1599 | | // rotate the unit vector by -45 degrees and add to point 1 |
| 1600 | | vertex[3].x = b1.x1 + step->xoffs; |
| 1601 | | vertex[3].y = b1.y1 + step->yoffs; |
| 1602 | | |
| 1603 | | // determine the color of the line |
| 1604 | | INT32 r = (INT32)(prim->color.r * step->weight * 255.0f); |
| 1605 | | INT32 g = (INT32)(prim->color.g * step->weight * 255.0f); |
| 1606 | | INT32 b = (INT32)(prim->color.b * step->weight * 255.0f); |
| 1607 | | INT32 a = (INT32)(prim->color.a * 255.0f); |
| 1608 | | if (r > 255) r = 255; |
| 1609 | | if (g > 255) g = 255; |
| 1610 | | if (b > 255) b = 255; |
| 1611 | | if (a > 255) a = 255; |
| 1612 | | DWORD color = D3DCOLOR_ARGB(a, r, g, b); |
| 1613 | | |
| 1614 | | vec2f& start = (get_vector_texture() ? get_vector_texture()->get_uvstart() : get_default_texture()->get_uvstart()); |
| 1615 | | vec2f& stop = (get_vector_texture() ? get_vector_texture()->get_uvstop() : get_default_texture()->get_uvstop()); |
| 1616 | | |
| 1617 | | vertex[0].u0 = start.c.x; |
| 1618 | | vertex[0].v0 = start.c.y; |
| 1619 | | |
| 1620 | | vertex[2].u0 = stop.c.x; |
| 1621 | | vertex[2].v0 = start.c.y; |
| 1622 | | |
| 1623 | | vertex[1].u0 = start.c.x; |
| 1624 | | vertex[1].v0 = stop.c.y; |
| 1625 | | |
| 1626 | | vertex[3].u0 = stop.c.x; |
| 1627 | | vertex[3].v0 = stop.c.y; |
| 1628 | | |
| 1629 | | // set the color, Z parameters to standard values |
| 1630 | | for (int i = 0; i < 4; i++) |
| 1631 | | { |
| 1632 | | vertex[i].z = 0.0f; |
| 1633 | | vertex[i].rhw = 1.0f; |
| 1634 | | vertex[i].color = color; |
| 1635 | | } |
| 1636 | | |
| 1637 | | // now add a polygon entry |
| 1638 | | m_poly[m_numpolys].init(D3DPT_TRIANGLESTRIP, 2, 4, prim->flags, get_vector_texture(), |
| 1639 | | D3DTOP_MODULATE, 0.0f, 1.0f, 0.0f, 0.0f); |
| 1640 | | m_numpolys++; |
| 1641 | | } |
| 1642 | | } |
| 1643 | | |
| 1644 | | |
| 1645 | | //============================================================ |
| 1646 | | // draw_quad |
| 1647 | | //============================================================ |
| 1648 | | |
| 1649 | | void renderer::draw_quad(const render_primitive *prim) |
| 1650 | | { |
| 1651 | | texture_info *texture = m_texture_manager->find_texinfo(&prim->texture, prim->flags); |
| 1652 | | |
| 1653 | | if (texture == NULL) |
| 1654 | | { |
| 1655 | | texture = get_default_texture(); |
| 1656 | | } |
| 1657 | | |
| 1658 | | // get a pointer to the vertex buffer |
| 1659 | | vertex *vertex = mesh_alloc(4); |
| 1660 | | if (vertex == NULL) |
| 1661 | | return; |
| 1662 | | |
| 1663 | | // fill in the vertexes clockwise |
| 1664 | | vertex[0].x = prim->bounds.x0; |
| 1665 | | vertex[0].y = prim->bounds.y0; |
| 1666 | | vertex[1].x = prim->bounds.x1; |
| 1667 | | vertex[1].y = prim->bounds.y0; |
| 1668 | | vertex[2].x = prim->bounds.x0; |
| 1669 | | vertex[2].y = prim->bounds.y1; |
| 1670 | | vertex[3].x = prim->bounds.x1; |
| 1671 | | vertex[3].y = prim->bounds.y1; |
| 1672 | | float width = prim->bounds.x1 - prim->bounds.x0; |
| 1673 | | float height = prim->bounds.y1 - prim->bounds.y0; |
| 1674 | | |
| 1675 | | // set the texture coordinates |
| 1676 | | if(texture != NULL) |
| 1677 | | { |
| 1678 | | vec2f& start = texture->get_uvstart(); |
| 1679 | | vec2f& stop = texture->get_uvstop(); |
| 1680 | | vec2f delta = stop - start; |
| 1681 | | vertex[0].u0 = start.c.x + delta.c.x * prim->texcoords.tl.u; |
| 1682 | | vertex[0].v0 = start.c.y + delta.c.y * prim->texcoords.tl.v; |
| 1683 | | vertex[1].u0 = start.c.x + delta.c.x * prim->texcoords.tr.u; |
| 1684 | | vertex[1].v0 = start.c.y + delta.c.y * prim->texcoords.tr.v; |
| 1685 | | vertex[2].u0 = start.c.x + delta.c.x * prim->texcoords.bl.u; |
| 1686 | | vertex[2].v0 = start.c.y + delta.c.y * prim->texcoords.bl.v; |
| 1687 | | vertex[3].u0 = start.c.x + delta.c.x * prim->texcoords.br.u; |
| 1688 | | vertex[3].v0 = start.c.y + delta.c.y * prim->texcoords.br.v; |
| 1689 | | } |
| 1690 | | |
| 1691 | | // determine the color, allowing for over modulation |
| 1692 | | INT32 r = (INT32)(prim->color.r * 255.0f); |
| 1693 | | INT32 g = (INT32)(prim->color.g * 255.0f); |
| 1694 | | INT32 b = (INT32)(prim->color.b * 255.0f); |
| 1695 | | INT32 a = (INT32)(prim->color.a * 255.0f); |
| 1696 | | DWORD modmode = D3DTOP_MODULATE; |
| 1697 | | if (texture != NULL) |
| 1698 | | { |
| 1699 | | if (m_mod2x_supported && (r > 255 || g > 255 || b > 255)) |
| 1700 | | { |
| 1701 | | if (m_mod4x_supported && (r > 2*255 || g > 2*255 || b > 2*255)) |
| 1702 | | { |
| 1703 | | r >>= 2; g >>= 2; b >>= 2; |
| 1704 | | modmode = D3DTOP_MODULATE4X; |
| 1705 | | } |
| 1706 | | else |
| 1707 | | { |
| 1708 | | r >>= 1; g >>= 1; b >>= 1; |
| 1709 | | modmode = D3DTOP_MODULATE2X; |
| 1710 | | } |
| 1711 | | } |
| 1712 | | } |
| 1713 | | if (r > 255) r = 255; |
| 1714 | | if (g > 255) g = 255; |
| 1715 | | if (b > 255) b = 255; |
| 1716 | | if (a > 255) a = 255; |
| 1717 | | DWORD color = D3DCOLOR_ARGB(a, r, g, b); |
| 1718 | | |
| 1719 | | // adjust half pixel X/Y offset, set the color, Z parameters to standard values |
| 1720 | | for (int i = 0; i < 4; i++) |
| 1721 | | { |
| 1722 | | vertex[i].x -= 0.5f; |
| 1723 | | vertex[i].y -= 0.5f; |
| 1724 | | vertex[i].z = 0.0f; |
| 1725 | | vertex[i].rhw = 1.0f; |
| 1726 | | vertex[i].color = color; |
| 1727 | | } |
| 1728 | | |
| 1729 | | // now add a polygon entry |
| 1730 | | m_poly[m_numpolys].init(D3DPT_TRIANGLESTRIP, 2, 4, prim->flags, texture, modmode, width, height); |
| 1731 | | m_numpolys++; |
| 1732 | | } |
| 1733 | | |
| 1734 | | void poly_info::init(D3DPRIMITIVETYPE type, UINT32 count, UINT32 numverts, |
| 1735 | | UINT32 flags, texture_info *texture, UINT32 modmode, |
| 1736 | | float line_time, float line_length, |
| 1737 | | float prim_width, float prim_height) |
| 1738 | | { |
| 1739 | | init(type, count, numverts, flags, texture, modmode, prim_width, prim_height); |
| 1740 | | m_line_time = line_time; |
| 1741 | | m_line_length = line_length; |
| 1742 | | } |
| 1743 | | |
| 1744 | | void poly_info::init(D3DPRIMITIVETYPE type, UINT32 count, UINT32 numverts, |
| 1745 | | UINT32 flags, texture_info *texture, UINT32 modmode, |
| 1746 | | float prim_width, float prim_height) |
| 1747 | | { |
| 1748 | | m_type = type; |
| 1749 | | m_count = count; |
| 1750 | | m_numverts = numverts; |
| 1751 | | m_flags = flags; |
| 1752 | | m_texture = texture; |
| 1753 | | m_modmode = modmode; |
| 1754 | | m_prim_width = prim_width; |
| 1755 | | m_prim_height = prim_height; |
| 1756 | | } |
| 1757 | | |
| 1758 | | |
| 1759 | | //============================================================ |
| 1760 | | // primitive_alloc |
| 1761 | | //============================================================ |
| 1762 | | |
| 1763 | | vertex *renderer::mesh_alloc(int numverts) |
| 1764 | | { |
| 1765 | | HRESULT result; |
| 1766 | | |
| 1767 | | // if we're going to overflow, flush |
| 1768 | | if (m_lockedbuf != NULL && m_numverts + numverts >= VERTEX_BUFFER_SIZE) |
| 1769 | | { |
| 1770 | | primitive_flush_pending(); |
| 1771 | | |
| 1772 | | if(m_shaders->enabled()) |
| 1773 | | { |
| 1774 | | m_hlsl_buf = (void*)mesh_alloc(6); |
| 1775 | | m_shaders->init_fsfx_quad(m_hlsl_buf); |
| 1776 | | } |
| 1777 | | } |
| 1778 | | |
| 1779 | | // if we don't have a lock, grab it now |
| 1780 | | if (m_lockedbuf == NULL) |
| 1781 | | { |
| 1782 | | result = (*d3dintf->vertexbuf.lock)(m_vertexbuf, 0, 0, (VOID **)&m_lockedbuf, D3DLOCK_DISCARD); |
| 1783 | | if (result != D3D_OK) |
| 1784 | | return NULL; |
| 1785 | | } |
| 1786 | | |
| 1787 | | // if we already have the lock and enough room, just return a pointer |
| 1788 | | if (m_lockedbuf != NULL && m_numverts + numverts < VERTEX_BUFFER_SIZE) |
| 1789 | | { |
| 1790 | | int oldverts = m_numverts; |
| 1791 | | m_numverts += numverts; |
| 1792 | | return &m_lockedbuf[oldverts]; |
| 1793 | | } |
| 1794 | | return NULL; |
| 1795 | | } |
| 1796 | | |
| 1797 | | |
| 1798 | | //============================================================ |
| 1799 | | // primitive_flush_pending |
| 1800 | | //============================================================ |
| 1801 | | |
| 1802 | | void renderer::primitive_flush_pending() |
| 1803 | | { |
| 1804 | | // ignore if we're not locked |
| 1805 | | if (m_lockedbuf == NULL) |
| 1806 | | { |
| 1807 | | return; |
| 1808 | | } |
| 1809 | | |
| 1810 | | // unlock the buffer |
| 1811 | | HRESULT result = (*d3dintf->vertexbuf.unlock)(m_vertexbuf); |
| 1812 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during vertex buffer unlock call\n", (int)result); |
| 1813 | | m_lockedbuf = NULL; |
| 1814 | | |
| 1815 | | // set the stream |
| 1816 | | result = (*d3dintf->device.set_stream_source)(m_device, 0, m_vertexbuf, sizeof(vertex)); |
| 1817 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_stream_source call\n", (int)result); |
| 1818 | | |
| 1819 | | m_shaders->begin_draw(); |
| 1820 | | |
| 1821 | | int vertnum = 0; |
| 1822 | | if (m_shaders->enabled()) |
| 1823 | | { |
| 1824 | | vertnum = 6; |
| 1825 | | } |
| 1826 | | |
| 1827 | | // now do the polys |
| 1828 | | for (int polynum = 0; polynum < m_numpolys; polynum++) |
| 1829 | | { |
| 1830 | | UINT32 flags = m_poly[polynum].get_flags(); |
| 1831 | | texture_info *texture = m_poly[polynum].get_texture(); |
| 1832 | | int newfilter; |
| 1833 | | |
| 1834 | | // set the texture if different |
| 1835 | | set_texture(texture); |
| 1836 | | |
| 1837 | | // set filtering if different |
| 1838 | | if (texture != NULL) |
| 1839 | | { |
| 1840 | | newfilter = FALSE; |
| 1841 | | if (PRIMFLAG_GET_SCREENTEX(flags)) |
| 1842 | | newfilter = video_config.filter; |
| 1843 | | set_filter(newfilter); |
| 1844 | | set_wrap(PRIMFLAG_GET_TEXWRAP(flags) ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP); |
| 1845 | | set_modmode(m_poly[polynum].get_modmode()); |
| 1846 | | |
| 1847 | | m_shaders->init_effect_info(&m_poly[polynum]); |
| 1848 | | } |
| 1849 | | |
| 1850 | | // set the blendmode if different |
| 1851 | | set_blendmode(PRIMFLAG_GET_BLENDMODE(flags)); |
| 1852 | | |
| 1853 | | if (vertnum + m_poly[polynum].get_vertcount() > m_numverts) |
| 1854 | | { |
| 1855 | | osd_printf_error("Error: vertnum (%d) plus poly vertex count (%d) > %d\n", vertnum, m_poly[polynum].get_vertcount(), m_numverts); |
| 1856 | | fflush(stdout); |
| 1857 | | } |
| 1858 | | |
| 1859 | | assert(vertnum + m_poly[polynum].get_vertcount() <= m_numverts); |
| 1860 | | |
| 1861 | | if(m_shaders->enabled() && d3dintf->post_fx_available) |
| 1862 | | { |
| 1863 | | m_shaders->render_quad(&m_poly[polynum], vertnum); |
| 1864 | | } |
| 1865 | | else |
| 1866 | | { |
| 1867 | | // add the primitives |
| 1868 | | result = (*d3dintf->device.draw_primitive)(m_device, m_poly[polynum].get_type(), vertnum, |
| 1869 | | m_poly[polynum].get_count()); |
| 1870 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device draw_primitive call\n", (int)result); |
| 1871 | | } |
| 1872 | | |
| 1873 | | vertnum += m_poly[polynum].get_vertcount(); |
| 1874 | | } |
| 1875 | | |
| 1876 | | m_shaders->end_draw(); |
| 1877 | | |
| 1878 | | // reset the vertex count |
| 1879 | | m_numverts = 0; |
| 1880 | | m_numpolys = 0; |
| 1881 | | } |
| 1882 | | |
| 1883 | | |
| 1884 | | //============================================================ |
| 1885 | | // texture_info destructor |
| 1886 | | //============================================================ |
| 1887 | | |
| 1888 | | texture_info::~texture_info() |
| 1889 | | { |
| 1890 | | if (m_d3dfinaltex != NULL) |
| 1891 | | { |
| 1892 | | if (m_d3dtex == m_d3dfinaltex) |
| 1893 | | { |
| 1894 | | m_d3dtex = NULL; |
| 1895 | | } |
| 1896 | | (*d3dintf->texture.release)(m_d3dfinaltex); |
| 1897 | | m_d3dfinaltex = NULL; |
| 1898 | | } |
| 1899 | | if (m_d3dtex != NULL) |
| 1900 | | { |
| 1901 | | (*d3dintf->texture.release)(m_d3dtex); |
| 1902 | | m_d3dtex = NULL; |
| 1903 | | } |
| 1904 | | if (m_d3dsurface != NULL) |
| 1905 | | { |
| 1906 | | (*d3dintf->surface.release)(m_d3dsurface); |
| 1907 | | m_d3dsurface = NULL; |
| 1908 | | } |
| 1909 | | } |
| 1910 | | |
| 1911 | | |
| 1912 | | //============================================================ |
| 1913 | | // texture_info constructor |
| 1914 | | //============================================================ |
| 1915 | | |
| 1916 | | texture_info::texture_info(texture_manager *manager, const render_texinfo* texsource, int prescale, UINT32 flags) |
| 1917 | | { |
| 1918 | | HRESULT result; |
| 1919 | | |
| 1920 | | // fill in the core data |
| 1921 | | m_texture_manager = manager; |
| 1922 | | m_renderer = m_texture_manager->get_d3d(); |
| 1923 | | m_hash = m_texture_manager->texture_compute_hash(texsource, flags); |
| 1924 | | m_flags = flags; |
| 1925 | | m_texinfo = *texsource; |
| 1926 | | m_xprescale = prescale; |
| 1927 | | m_yprescale = prescale; |
| 1928 | | |
| 1929 | | m_d3dtex = NULL; |
| 1930 | | m_d3dsurface = NULL; |
| 1931 | | m_d3dfinaltex = NULL; |
| 1932 | | |
| 1933 | | // compute the size |
| 1934 | | compute_size(texsource->width, texsource->height); |
| 1935 | | |
| 1936 | | // non-screen textures are easy |
| 1937 | | if (!PRIMFLAG_GET_SCREENTEX(flags)) |
| 1938 | | { |
| 1939 | | assert(PRIMFLAG_TEXFORMAT(flags) != TEXFORMAT_YUY16); |
| 1940 | | result = (*d3dintf->device.create_texture)(m_renderer->get_device(), m_rawdims.c.x, m_rawdims.c.y, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_d3dtex); |
| 1941 | | if (result != D3D_OK) |
| 1942 | | goto error; |
| 1943 | | m_d3dfinaltex = m_d3dtex; |
| 1944 | | m_type = TEXTURE_TYPE_PLAIN; |
| 1945 | | } |
| 1946 | | |
| 1947 | | // screen textures are allocated differently |
| 1948 | | else |
| 1949 | | { |
| 1950 | | D3DFORMAT format; |
| 1951 | | DWORD usage = m_texture_manager->is_dynamic_supported() ? D3DUSAGE_DYNAMIC : 0; |
| 1952 | | D3DPOOL pool = m_texture_manager->is_dynamic_supported() ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED; |
| 1953 | | int maxdim = MAX(m_renderer->get_presentation()->BackBufferWidth, m_renderer->get_presentation()->BackBufferHeight); |
| 1954 | | |
| 1955 | | // pick the format |
| 1956 | | if (PRIMFLAG_GET_TEXFORMAT(flags) == TEXFORMAT_YUY16) |
| 1957 | | { |
| 1958 | | format = m_texture_manager->get_yuv_format(); |
| 1959 | | } |
| 1960 | | else if (PRIMFLAG_GET_TEXFORMAT(flags) == TEXFORMAT_ARGB32 || PRIMFLAG_GET_TEXFORMAT(flags) == TEXFORMAT_PALETTEA16) |
| 1961 | | { |
| 1962 | | format = D3DFMT_A8R8G8B8; |
| 1963 | | } |
| 1964 | | else |
| 1965 | | { |
| 1966 | | format = m_renderer->get_screen_format(); |
| 1967 | | } |
| 1968 | | |
| 1969 | | // don't prescale above screen size |
| 1970 | | while (m_xprescale > 1 && m_rawdims.c.x * m_xprescale >= 2 * maxdim) |
| 1971 | | { |
| 1972 | | m_xprescale--; |
| 1973 | | } |
| 1974 | | while (m_xprescale > 1 && m_rawdims.c.x * m_xprescale > manager->get_max_texture_width()) |
| 1975 | | { |
| 1976 | | m_xprescale--; |
| 1977 | | } |
| 1978 | | while (m_yprescale > 1 && m_rawdims.c.y * m_yprescale >= 2 * maxdim) |
| 1979 | | { |
| 1980 | | m_yprescale--; |
| 1981 | | } |
| 1982 | | while (m_yprescale > 1 && m_rawdims.c.y * m_yprescale > manager->get_max_texture_height()) |
| 1983 | | { |
| 1984 | | m_yprescale--; |
| 1985 | | } |
| 1986 | | |
| 1987 | | int prescale = m_renderer->window().prescale(); |
| 1988 | | if (m_xprescale != prescale || m_yprescale != prescale) |
| 1989 | | { |
| 1990 | | osd_printf_verbose("Direct3D: adjusting prescale from %dx%d to %dx%d\n", prescale, prescale, m_xprescale, m_yprescale); |
| 1991 | | } |
| 1992 | | |
| 1993 | | // loop until we allocate something or error |
| 1994 | | for (int attempt = 0; attempt < 2; attempt++) |
| 1995 | | { |
| 1996 | | // second attempt is always 1:1 |
| 1997 | | if (attempt == 1) |
| 1998 | | { |
| 1999 | | m_xprescale = m_yprescale = 1; |
| 2000 | | } |
| 2001 | | |
| 2002 | | // screen textures with no prescaling are pretty easy |
| 2003 | | if (m_xprescale == 1 && m_yprescale == 1) |
| 2004 | | { |
| 2005 | | result = (*d3dintf->device.create_texture)(m_renderer->get_device(), m_rawdims.c.x, m_rawdims.c.y, 1, usage, format, pool, &m_d3dtex); |
| 2006 | | if (result == D3D_OK) |
| 2007 | | { |
| 2008 | | m_d3dfinaltex = m_d3dtex; |
| 2009 | | m_type = m_texture_manager->is_dynamic_supported() ? TEXTURE_TYPE_DYNAMIC : TEXTURE_TYPE_PLAIN; |
| 2010 | | if (m_renderer->get_shaders()->enabled() && !m_renderer->get_shaders()->register_texture(this)) |
| 2011 | | { |
| 2012 | | goto error; |
| 2013 | | } |
| 2014 | | |
| 2015 | | break; |
| 2016 | | } |
| 2017 | | } |
| 2018 | | |
| 2019 | | // screen textures with prescaling require two allocations |
| 2020 | | else |
| 2021 | | { |
| 2022 | | // use an offscreen plain surface for stretching if supported |
| 2023 | | // (won't work for YUY textures) |
| 2024 | | if (m_texture_manager->is_stretch_supported() && PRIMFLAG_GET_TEXFORMAT(flags) != TEXFORMAT_YUY16) |
| 2025 | | { |
| 2026 | | result = (*d3dintf->device.create_offscreen_plain_surface)(m_renderer->get_device(), m_rawdims.c.x, m_rawdims.c.y, format, D3DPOOL_DEFAULT, &m_d3dsurface); |
| 2027 | | if (result != D3D_OK) |
| 2028 | | { |
| 2029 | | continue; |
| 2030 | | } |
| 2031 | | m_type = TEXTURE_TYPE_SURFACE; |
| 2032 | | } |
| 2033 | | |
| 2034 | | // otherwise, we allocate a dynamic texture for the source |
| 2035 | | else |
| 2036 | | { |
| 2037 | | result = (*d3dintf->device.create_texture)(m_renderer->get_device(), m_rawdims.c.x, m_rawdims.c.y, 1, usage, format, pool, &m_d3dtex); |
| 2038 | | if (result != D3D_OK) |
| 2039 | | { |
| 2040 | | continue; |
| 2041 | | } |
| 2042 | | m_type = m_texture_manager->is_dynamic_supported() ? TEXTURE_TYPE_DYNAMIC : TEXTURE_TYPE_PLAIN; |
| 2043 | | } |
| 2044 | | |
| 2045 | | // for the target surface, we allocate a render target texture |
| 2046 | | int scwidth = m_rawdims.c.x * m_xprescale; |
| 2047 | | int scheight = m_rawdims.c.y * m_yprescale; |
| 2048 | | |
| 2049 | | // target surfaces typically cannot be YCbCr, so we always pick RGB in that case |
| 2050 | | D3DFORMAT finalfmt = (format != m_texture_manager->get_yuv_format()) ? format : D3DFMT_A8R8G8B8; |
| 2051 | | result = (*d3dintf->device.create_texture)(m_renderer->get_device(), scwidth, scheight, 1, D3DUSAGE_RENDERTARGET, finalfmt, D3DPOOL_DEFAULT, &m_d3dfinaltex); |
| 2052 | | if (result == D3D_OK) |
| 2053 | | { |
| 2054 | | if (m_renderer->get_shaders()->enabled() && !m_renderer->get_shaders()->register_prescaled_texture(this)) |
| 2055 | | { |
| 2056 | | goto error; |
| 2057 | | } |
| 2058 | | break; |
| 2059 | | } |
| 2060 | | (*d3dintf->texture.release)(m_d3dtex); |
| 2061 | | m_d3dtex = NULL; |
| 2062 | | } |
| 2063 | | } |
| 2064 | | } |
| 2065 | | |
| 2066 | | // copy the data to the texture |
| 2067 | | set_data(texsource, flags); |
| 2068 | | |
| 2069 | | //texsource->osdhandle = (void*)this; |
| 2070 | | // add us to the texture list |
| 2071 | | if(m_texture_manager->get_texlist() != NULL) |
| 2072 | | m_texture_manager->get_texlist()->m_prev = this; |
| 2073 | | m_prev = NULL; |
| 2074 | | m_next = m_texture_manager->get_texlist(); |
| 2075 | | m_texture_manager->set_texlist(this); |
| 2076 | | return; |
| 2077 | | |
| 2078 | | error: |
| 2079 | | d3dintf->post_fx_available = false; |
| 2080 | | osd_printf_error("Direct3D: Critical warning: A texture failed to allocate. Expect things to get bad quickly.\n"); |
| 2081 | | if (m_d3dsurface != NULL) |
| 2082 | | (*d3dintf->surface.release)(m_d3dsurface); |
| 2083 | | if (m_d3dtex != NULL) |
| 2084 | | (*d3dintf->texture.release)(m_d3dtex); |
| 2085 | | } |
| 2086 | | |
| 2087 | | |
| 2088 | | //============================================================ |
| 2089 | | // texture_info::compute_size_subroutine |
| 2090 | | //============================================================ |
| 2091 | | |
| 2092 | | void texture_info::compute_size_subroutine(int texwidth, int texheight, int* p_width, int* p_height) |
| 2093 | | { |
| 2094 | | int finalheight = texheight; |
| 2095 | | int finalwidth = texwidth; |
| 2096 | | |
| 2097 | | // round width/height up to nearest power of 2 if we need to |
| 2098 | | if (!(m_texture_manager->get_texture_caps() & D3DPTEXTURECAPS_NONPOW2CONDITIONAL)) |
| 2099 | | { |
| 2100 | | // first the width |
| 2101 | | if (finalwidth & (finalwidth - 1)) |
| 2102 | | { |
| 2103 | | finalwidth |= finalwidth >> 1; |
| 2104 | | finalwidth |= finalwidth >> 2; |
| 2105 | | finalwidth |= finalwidth >> 4; |
| 2106 | | finalwidth |= finalwidth >> 8; |
| 2107 | | finalwidth++; |
| 2108 | | } |
| 2109 | | |
| 2110 | | // then the height |
| 2111 | | if (finalheight & (finalheight - 1)) |
| 2112 | | { |
| 2113 | | finalheight |= finalheight >> 1; |
| 2114 | | finalheight |= finalheight >> 2; |
| 2115 | | finalheight |= finalheight >> 4; |
| 2116 | | finalheight |= finalheight >> 8; |
| 2117 | | finalheight++; |
| 2118 | | } |
| 2119 | | } |
| 2120 | | |
| 2121 | | // round up to square if we need to |
| 2122 | | if (m_texture_manager->get_texture_caps() & D3DPTEXTURECAPS_SQUAREONLY) |
| 2123 | | { |
| 2124 | | if (finalwidth < finalheight) |
| 2125 | | finalwidth = finalheight; |
| 2126 | | else |
| 2127 | | finalheight = finalwidth; |
| 2128 | | } |
| 2129 | | |
| 2130 | | // adjust the aspect ratio if we need to |
| 2131 | | while (finalwidth < finalheight && finalheight / finalwidth > m_texture_manager->get_max_texture_aspect()) |
| 2132 | | { |
| 2133 | | finalwidth *= 2; |
| 2134 | | } |
| 2135 | | while (finalheight < finalwidth && finalwidth / finalheight > m_texture_manager->get_max_texture_aspect()) |
| 2136 | | { |
| 2137 | | finalheight *= 2; |
| 2138 | | } |
| 2139 | | |
| 2140 | | *p_width = finalwidth; |
| 2141 | | *p_height = finalheight; |
| 2142 | | } |
| 2143 | | |
| 2144 | | |
| 2145 | | //============================================================ |
| 2146 | | // texture_info::compute_size |
| 2147 | | //============================================================ |
| 2148 | | |
| 2149 | | void texture_info::compute_size(int texwidth, int texheight) |
| 2150 | | { |
| 2151 | | int finalheight = texheight; |
| 2152 | | int finalwidth = texwidth; |
| 2153 | | |
| 2154 | | m_xborderpix = 0; |
| 2155 | | m_yborderpix = 0; |
| 2156 | | |
| 2157 | | // if we're not wrapping, add a 1-2 pixel border on all sides |
| 2158 | | if (ENABLE_BORDER_PIX && !(m_flags & PRIMFLAG_TEXWRAP_MASK)) |
| 2159 | | { |
| 2160 | | // note we need 2 pixels in X for YUY textures |
| 2161 | | m_xborderpix = (PRIMFLAG_GET_TEXFORMAT(m_flags) == TEXFORMAT_YUY16) ? 2 : 1; |
| 2162 | | m_yborderpix = 1; |
| 2163 | | } |
| 2164 | | |
| 2165 | | // compute final texture size |
| 2166 | | finalwidth += 2 * m_xborderpix; |
| 2167 | | finalheight += 2 * m_yborderpix; |
| 2168 | | |
| 2169 | | compute_size_subroutine(finalwidth, finalheight, &finalwidth, &finalheight); |
| 2170 | | |
| 2171 | | // if we added pixels for the border, and that just barely pushed us over, take it back |
| 2172 | | if (finalwidth > m_texture_manager->get_max_texture_width() || finalheight > m_texture_manager->get_max_texture_height()) |
| 2173 | | { |
| 2174 | | finalheight = texheight; |
| 2175 | | finalwidth = texwidth; |
| 2176 | | |
| 2177 | | m_xborderpix = 0; |
| 2178 | | m_yborderpix = 0; |
| 2179 | | |
| 2180 | | compute_size_subroutine(finalwidth, finalheight, &finalwidth, &finalheight); |
| 2181 | | } |
| 2182 | | |
| 2183 | | // if we're above the max width/height, do what? |
| 2184 | | if (finalwidth > m_texture_manager->get_max_texture_width() || finalheight > m_texture_manager->get_max_texture_height()) |
| 2185 | | { |
| 2186 | | static int printed = FALSE; |
| 2187 | | if (!printed) osd_printf_warning("Texture too big! (wanted: %dx%d, max is %dx%d)\n", finalwidth, finalheight, (int)m_texture_manager->get_max_texture_width(), (int)m_texture_manager->get_max_texture_height()); |
| 2188 | | printed = TRUE; |
| 2189 | | } |
| 2190 | | |
| 2191 | | // compute the U/V scale factors |
| 2192 | | m_start.c.x = (float)m_xborderpix / (float)finalwidth; |
| 2193 | | m_start.c.y = (float)m_yborderpix / (float)finalheight; |
| 2194 | | m_stop.c.x = (float)(texwidth + m_xborderpix) / (float)finalwidth; |
| 2195 | | m_stop.c.y = (float)(texheight + m_yborderpix) / (float)finalheight; |
| 2196 | | |
| 2197 | | // set the final values |
| 2198 | | m_rawdims.c.x = finalwidth; |
| 2199 | | m_rawdims.c.y = finalheight; |
| 2200 | | } |
| 2201 | | |
| 2202 | | |
| 2203 | | //============================================================ |
| 2204 | | // copyline_palette16 |
| 2205 | | //============================================================ |
| 2206 | | |
| 2207 | | INLINE void copyline_palette16(UINT32 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix) |
| 2208 | | { |
| 2209 | | int x; |
| 2210 | | |
| 2211 | | assert(xborderpix == 0 || xborderpix == 1); |
| 2212 | | if (xborderpix) |
| 2213 | | *dst++ = 0xff000000 | palette[*src]; |
| 2214 | | for (x = 0; x < width; x++) |
| 2215 | | *dst++ = 0xff000000 | palette[*src++]; |
| 2216 | | if (xborderpix) |
| 2217 | | *dst++ = 0xff000000 | palette[*--src]; |
| 2218 | | } |
| 2219 | | |
| 2220 | | |
| 2221 | | //============================================================ |
| 2222 | | // copyline_palettea16 |
| 2223 | | //============================================================ |
| 2224 | | |
| 2225 | | INLINE void copyline_palettea16(UINT32 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix) |
| 2226 | | { |
| 2227 | | int x; |
| 2228 | | |
| 2229 | | assert(xborderpix == 0 || xborderpix == 1); |
| 2230 | | if (xborderpix) |
| 2231 | | *dst++ = palette[*src]; |
| 2232 | | for (x = 0; x < width; x++) |
| 2233 | | *dst++ = palette[*src++]; |
| 2234 | | if (xborderpix) |
| 2235 | | *dst++ = palette[*--src]; |
| 2236 | | } |
| 2237 | | |
| 2238 | | |
| 2239 | | //============================================================ |
| 2240 | | // copyline_rgb32 |
| 2241 | | //============================================================ |
| 2242 | | |
| 2243 | | INLINE void copyline_rgb32(UINT32 *dst, const UINT32 *src, int width, const rgb_t *palette, int xborderpix) |
| 2244 | | { |
| 2245 | | int x; |
| 2246 | | |
| 2247 | | assert(xborderpix == 0 || xborderpix == 1); |
| 2248 | | |
| 2249 | | // palette (really RGB map) case |
| 2250 | | if (palette != NULL) |
| 2251 | | { |
| 2252 | | if (xborderpix) |
| 2253 | | { |
| 2254 | | rgb_t srcpix = *src; |
| 2255 | | *dst++ = 0xff000000 | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()]; |
| 2256 | | } |
| 2257 | | for (x = 0; x < width; x++) |
| 2258 | | { |
| 2259 | | rgb_t srcpix = *src++; |
| 2260 | | *dst++ = 0xff000000 | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()]; |
| 2261 | | } |
| 2262 | | if (xborderpix) |
| 2263 | | { |
| 2264 | | rgb_t srcpix = *--src; |
| 2265 | | *dst++ = 0xff000000 | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()]; |
| 2266 | | } |
| 2267 | | } |
| 2268 | | |
| 2269 | | // direct case |
| 2270 | | else |
| 2271 | | { |
| 2272 | | if (xborderpix) |
| 2273 | | *dst++ = 0xff000000 | *src; |
| 2274 | | for (x = 0; x < width; x++) |
| 2275 | | *dst++ = 0xff000000 | *src++; |
| 2276 | | if (xborderpix) |
| 2277 | | *dst++ = 0xff000000 | *--src; |
| 2278 | | } |
| 2279 | | } |
| 2280 | | |
| 2281 | | |
| 2282 | | //============================================================ |
| 2283 | | // copyline_argb32 |
| 2284 | | //============================================================ |
| 2285 | | |
| 2286 | | INLINE void copyline_argb32(UINT32 *dst, const UINT32 *src, int width, const rgb_t *palette, int xborderpix) |
| 2287 | | { |
| 2288 | | int x; |
| 2289 | | |
| 2290 | | assert(xborderpix == 0 || xborderpix == 1); |
| 2291 | | |
| 2292 | | // palette (really RGB map) case |
| 2293 | | if (palette != NULL) |
| 2294 | | { |
| 2295 | | if (xborderpix) |
| 2296 | | { |
| 2297 | | rgb_t srcpix = *src; |
| 2298 | | *dst++ = (srcpix & 0xff000000) | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()]; |
| 2299 | | } |
| 2300 | | for (x = 0; x < width; x++) |
| 2301 | | { |
| 2302 | | rgb_t srcpix = *src++; |
| 2303 | | *dst++ = (srcpix & 0xff000000) | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()]; |
| 2304 | | } |
| 2305 | | if (xborderpix) |
| 2306 | | { |
| 2307 | | rgb_t srcpix = *--src; |
| 2308 | | *dst++ = (srcpix & 0xff000000) | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()]; |
| 2309 | | } |
| 2310 | | } |
| 2311 | | |
| 2312 | | // direct case |
| 2313 | | else |
| 2314 | | { |
| 2315 | | if (xborderpix) |
| 2316 | | *dst++ = *src; |
| 2317 | | for (x = 0; x < width; x++) |
| 2318 | | *dst++ = *src++; |
| 2319 | | if (xborderpix) |
| 2320 | | *dst++ = *--src; |
| 2321 | | } |
| 2322 | | } |
| 2323 | | |
| 2324 | | |
| 2325 | | //============================================================ |
| 2326 | | // copyline_yuy16_to_yuy2 |
| 2327 | | //============================================================ |
| 2328 | | |
| 2329 | | INLINE void copyline_yuy16_to_yuy2(UINT16 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix) |
| 2330 | | { |
| 2331 | | int x; |
| 2332 | | |
| 2333 | | assert(xborderpix == 0 || xborderpix == 2); |
| 2334 | | assert(width % 2 == 0); |
| 2335 | | |
| 2336 | | // palette (really RGB map) case |
| 2337 | | if (palette != NULL) |
| 2338 | | { |
| 2339 | | if (xborderpix) |
| 2340 | | { |
| 2341 | | UINT16 srcpix0 = *src++; |
| 2342 | | UINT16 srcpix1 = *src--; |
| 2343 | | *dst++ = palette[0x000 + (srcpix0 >> 8)] | (srcpix0 << 8); |
| 2344 | | *dst++ = palette[0x000 + (srcpix0 >> 8)] | (srcpix1 << 8); |
| 2345 | | } |
| 2346 | | for (x = 0; x < width; x += 2) |
| 2347 | | { |
| 2348 | | UINT16 srcpix0 = *src++; |
| 2349 | | UINT16 srcpix1 = *src++; |
| 2350 | | *dst++ = palette[0x000 + (srcpix0 >> 8)] | (srcpix0 << 8); |
| 2351 | | *dst++ = palette[0x000 + (srcpix1 >> 8)] | (srcpix1 << 8); |
| 2352 | | } |
| 2353 | | if (xborderpix) |
| 2354 | | { |
| 2355 | | UINT16 srcpix1 = *--src; |
| 2356 | | UINT16 srcpix0 = *--src; |
| 2357 | | *dst++ = palette[0x000 + (srcpix1 >> 8)] | (srcpix0 << 8); |
| 2358 | | *dst++ = palette[0x000 + (srcpix1 >> 8)] | (srcpix1 << 8); |
| 2359 | | } |
| 2360 | | } |
| 2361 | | |
| 2362 | | // direct case |
| 2363 | | else |
| 2364 | | { |
| 2365 | | if (xborderpix) |
| 2366 | | { |
| 2367 | | UINT16 srcpix0 = *src++; |
| 2368 | | UINT16 srcpix1 = *src--; |
| 2369 | | *dst++ = (srcpix0 >> 8) | (srcpix0 << 8); |
| 2370 | | *dst++ = (srcpix0 >> 8) | (srcpix1 << 8); |
| 2371 | | } |
| 2372 | | for (x = 0; x < width; x += 2) |
| 2373 | | { |
| 2374 | | UINT16 srcpix0 = *src++; |
| 2375 | | UINT16 srcpix1 = *src++; |
| 2376 | | *dst++ = (srcpix0 >> 8) | (srcpix0 << 8); |
| 2377 | | *dst++ = (srcpix1 >> 8) | (srcpix1 << 8); |
| 2378 | | } |
| 2379 | | if (xborderpix) |
| 2380 | | { |
| 2381 | | UINT16 srcpix1 = *--src; |
| 2382 | | UINT16 srcpix0 = *--src; |
| 2383 | | *dst++ = (srcpix1 >> 8) | (srcpix0 << 8); |
| 2384 | | *dst++ = (srcpix1 >> 8) | (srcpix1 << 8); |
| 2385 | | } |
| 2386 | | } |
| 2387 | | } |
| 2388 | | |
| 2389 | | |
| 2390 | | //============================================================ |
| 2391 | | // copyline_yuy16_to_uyvy |
| 2392 | | //============================================================ |
| 2393 | | |
| 2394 | | INLINE void copyline_yuy16_to_uyvy(UINT16 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix) |
| 2395 | | { |
| 2396 | | int x; |
| 2397 | | |
| 2398 | | assert(xborderpix == 0 || xborderpix == 2); |
| 2399 | | assert(width % 2 == 0); |
| 2400 | | |
| 2401 | | // palette (really RGB map) case |
| 2402 | | if (palette != NULL) |
| 2403 | | { |
| 2404 | | if (xborderpix) |
| 2405 | | { |
| 2406 | | UINT16 srcpix0 = *src++; |
| 2407 | | UINT16 srcpix1 = *src--; |
| 2408 | | *dst++ = palette[0x100 + (srcpix0 >> 8)] | (srcpix0 & 0xff); |
| 2409 | | *dst++ = palette[0x100 + (srcpix0 >> 8)] | (srcpix1 & 0xff); |
| 2410 | | } |
| 2411 | | for (x = 0; x < width; x += 2) |
| 2412 | | { |
| 2413 | | UINT16 srcpix0 = *src++; |
| 2414 | | UINT16 srcpix1 = *src++; |
| 2415 | | *dst++ = palette[0x100 + (srcpix0 >> 8)] | (srcpix0 & 0xff); |
| 2416 | | *dst++ = palette[0x100 + (srcpix1 >> 8)] | (srcpix1 & 0xff); |
| 2417 | | } |
| 2418 | | if (xborderpix) |
| 2419 | | { |
| 2420 | | UINT16 srcpix1 = *--src; |
| 2421 | | UINT16 srcpix0 = *--src; |
| 2422 | | *dst++ = palette[0x100 + (srcpix1 >> 8)] | (srcpix0 & 0xff); |
| 2423 | | *dst++ = palette[0x100 + (srcpix1 >> 8)] | (srcpix1 & 0xff); |
| 2424 | | } |
| 2425 | | } |
| 2426 | | |
| 2427 | | // direct case |
| 2428 | | else |
| 2429 | | { |
| 2430 | | if (xborderpix) |
| 2431 | | { |
| 2432 | | UINT16 srcpix0 = src[0]; |
| 2433 | | UINT16 srcpix1 = src[1]; |
| 2434 | | *dst++ = srcpix0; |
| 2435 | | *dst++ = (srcpix0 & 0xff00) | (srcpix1 & 0x00ff); |
| 2436 | | } |
| 2437 | | for (x = 0; x < width; x += 2) |
| 2438 | | { |
| 2439 | | *dst++ = *src++; |
| 2440 | | *dst++ = *src++; |
| 2441 | | } |
| 2442 | | if (xborderpix) |
| 2443 | | { |
| 2444 | | UINT16 srcpix1 = *--src; |
| 2445 | | UINT16 srcpix0 = *--src; |
| 2446 | | *dst++ = (srcpix1 & 0xff00) | (srcpix0 & 0x00ff); |
| 2447 | | *dst++ = srcpix1; |
| 2448 | | } |
| 2449 | | } |
| 2450 | | } |
| 2451 | | |
| 2452 | | |
| 2453 | | //============================================================ |
| 2454 | | // copyline_yuy16_to_argb |
| 2455 | | //============================================================ |
| 2456 | | |
| 2457 | | INLINE void copyline_yuy16_to_argb(UINT32 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix) |
| 2458 | | { |
| 2459 | | int x; |
| 2460 | | |
| 2461 | | assert(xborderpix == 0 || xborderpix == 2); |
| 2462 | | assert(width % 2 == 0); |
| 2463 | | |
| 2464 | | // palette (really RGB map) case |
| 2465 | | if (palette != NULL) |
| 2466 | | { |
| 2467 | | if (xborderpix) |
| 2468 | | { |
| 2469 | | UINT16 srcpix0 = src[0]; |
| 2470 | | UINT16 srcpix1 = src[1]; |
| 2471 | | UINT8 cb = srcpix0 & 0xff; |
| 2472 | | UINT8 cr = srcpix1 & 0xff; |
| 2473 | | *dst++ = ycc_to_rgb(palette[0x000 + (srcpix0 >> 8)], cb, cr); |
| 2474 | | *dst++ = ycc_to_rgb(palette[0x000 + (srcpix0 >> 8)], cb, cr); |
| 2475 | | } |
| 2476 | | for (x = 0; x < width / 2; x++) |
| 2477 | | { |
| 2478 | | UINT16 srcpix0 = *src++; |
| 2479 | | UINT16 srcpix1 = *src++; |
| 2480 | | UINT8 cb = srcpix0 & 0xff; |
| 2481 | | UINT8 cr = srcpix1 & 0xff; |
| 2482 | | *dst++ = ycc_to_rgb(palette[0x000 + (srcpix0 >> 8)], cb, cr); |
| 2483 | | *dst++ = ycc_to_rgb(palette[0x000 + (srcpix1 >> 8)], cb, cr); |
| 2484 | | } |
| 2485 | | if (xborderpix) |
| 2486 | | { |
| 2487 | | UINT16 srcpix1 = *--src; |
| 2488 | | UINT16 srcpix0 = *--src; |
| 2489 | | UINT8 cb = srcpix0 & 0xff; |
| 2490 | | UINT8 cr = srcpix1 & 0xff; |
| 2491 | | *dst++ = ycc_to_rgb(palette[0x000 + (srcpix1 >> 8)], cb, cr); |
| 2492 | | *dst++ = ycc_to_rgb(palette[0x000 + (srcpix1 >> 8)], cb, cr); |
| 2493 | | } |
| 2494 | | } |
| 2495 | | |
| 2496 | | // direct case |
| 2497 | | else |
| 2498 | | { |
| 2499 | | if (xborderpix) |
| 2500 | | { |
| 2501 | | UINT16 srcpix0 = src[0]; |
| 2502 | | UINT16 srcpix1 = src[1]; |
| 2503 | | UINT8 cb = srcpix0 & 0xff; |
| 2504 | | UINT8 cr = srcpix1 & 0xff; |
| 2505 | | *dst++ = ycc_to_rgb(srcpix0 >> 8, cb, cr); |
| 2506 | | *dst++ = ycc_to_rgb(srcpix0 >> 8, cb, cr); |
| 2507 | | } |
| 2508 | | for (x = 0; x < width; x += 2) |
| 2509 | | { |
| 2510 | | UINT16 srcpix0 = *src++; |
| 2511 | | UINT16 srcpix1 = *src++; |
| 2512 | | UINT8 cb = srcpix0 & 0xff; |
| 2513 | | UINT8 cr = srcpix1 & 0xff; |
| 2514 | | *dst++ = ycc_to_rgb(srcpix0 >> 8, cb, cr); |
| 2515 | | *dst++ = ycc_to_rgb(srcpix1 >> 8, cb, cr); |
| 2516 | | } |
| 2517 | | if (xborderpix) |
| 2518 | | { |
| 2519 | | UINT16 srcpix1 = *--src; |
| 2520 | | UINT16 srcpix0 = *--src; |
| 2521 | | UINT8 cb = srcpix0 & 0xff; |
| 2522 | | UINT8 cr = srcpix1 & 0xff; |
| 2523 | | *dst++ = ycc_to_rgb(srcpix1 >> 8, cb, cr); |
| 2524 | | *dst++ = ycc_to_rgb(srcpix1 >> 8, cb, cr); |
| 2525 | | } |
| 2526 | | } |
| 2527 | | } |
| 2528 | | |
| 2529 | | |
| 2530 | | //============================================================ |
| 2531 | | // texture_set_data |
| 2532 | | //============================================================ |
| 2533 | | |
| 2534 | | void texture_info::set_data(const render_texinfo *texsource, UINT32 flags) |
| 2535 | | { |
| 2536 | | D3DLOCKED_RECT rect; |
| 2537 | | HRESULT result; |
| 2538 | | |
| 2539 | | // lock the texture |
| 2540 | | switch (m_type) |
| 2541 | | { |
| 2542 | | default: |
| 2543 | | case TEXTURE_TYPE_PLAIN: result = (*d3dintf->texture.lock_rect)(m_d3dtex, 0, &rect, NULL, 0); break; |
| 2544 | | case TEXTURE_TYPE_DYNAMIC: result = (*d3dintf->texture.lock_rect)(m_d3dtex, 0, &rect, NULL, D3DLOCK_DISCARD); break; |
| 2545 | | case TEXTURE_TYPE_SURFACE: result = (*d3dintf->surface.lock_rect)(m_d3dsurface, &rect, NULL, D3DLOCK_DISCARD); break; |
| 2546 | | } |
| 2547 | | if (result != D3D_OK) |
| 2548 | | { |
| 2549 | | return; |
| 2550 | | } |
| 2551 | | |
| 2552 | | // loop over Y |
| 2553 | | int miny = 0 - m_yborderpix; |
| 2554 | | int maxy = texsource->height + m_yborderpix; |
| 2555 | | for (int dsty = miny; dsty < maxy; dsty++) |
| 2556 | | { |
| 2557 | | int srcy = (dsty < 0) ? 0 : (dsty >= texsource->height) ? texsource->height - 1 : dsty; |
| 2558 | | void *dst = (BYTE *)rect.pBits + (dsty + m_yborderpix) * rect.Pitch; |
| 2559 | | |
| 2560 | | // switch off of the format and |
| 2561 | | switch (PRIMFLAG_GET_TEXFORMAT(flags)) |
| 2562 | | { |
| 2563 | | case TEXFORMAT_PALETTE16: |
| 2564 | | copyline_palette16((UINT32 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix); |
| 2565 | | break; |
| 2566 | | |
| 2567 | | case TEXFORMAT_PALETTEA16: |
| 2568 | | copyline_palettea16((UINT32 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix); |
| 2569 | | break; |
| 2570 | | |
| 2571 | | case TEXFORMAT_RGB32: |
| 2572 | | copyline_rgb32((UINT32 *)dst, (UINT32 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix); |
| 2573 | | break; |
| 2574 | | |
| 2575 | | case TEXFORMAT_ARGB32: |
| 2576 | | copyline_argb32((UINT32 *)dst, (UINT32 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix); |
| 2577 | | break; |
| 2578 | | |
| 2579 | | case TEXFORMAT_YUY16: |
| 2580 | | if (m_texture_manager->get_yuv_format() == D3DFMT_YUY2) |
| 2581 | | copyline_yuy16_to_yuy2((UINT16 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix); |
| 2582 | | else if (m_texture_manager->get_yuv_format() == D3DFMT_UYVY) |
| 2583 | | copyline_yuy16_to_uyvy((UINT16 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix); |
| 2584 | | else |
| 2585 | | copyline_yuy16_to_argb((UINT32 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix); |
| 2586 | | break; |
| 2587 | | |
| 2588 | | default: |
| 2589 | | osd_printf_error("Unknown texture blendmode=%d format=%d\n", PRIMFLAG_GET_BLENDMODE(flags), PRIMFLAG_GET_TEXFORMAT(flags)); |
| 2590 | | break; |
| 2591 | | } |
| 2592 | | } |
| 2593 | | |
| 2594 | | // unlock |
| 2595 | | switch (m_type) |
| 2596 | | { |
| 2597 | | default: |
| 2598 | | case TEXTURE_TYPE_PLAIN: result = (*d3dintf->texture.unlock_rect)(m_d3dtex, 0); break; |
| 2599 | | case TEXTURE_TYPE_DYNAMIC: result = (*d3dintf->texture.unlock_rect)(m_d3dtex, 0); break; |
| 2600 | | case TEXTURE_TYPE_SURFACE: result = (*d3dintf->surface.unlock_rect)(m_d3dsurface); break; |
| 2601 | | } |
| 2602 | | if (result != D3D_OK) |
| 2603 | | { |
| 2604 | | osd_printf_verbose("Direct3D: Error %08X during texture unlock_rect call\n", (int)result); |
| 2605 | | } |
| 2606 | | |
| 2607 | | // prescale |
| 2608 | | prescale(); |
| 2609 | | } |
| 2610 | | |
| 2611 | | |
| 2612 | | //============================================================ |
| 2613 | | // texture_info::prescale |
| 2614 | | //============================================================ |
| 2615 | | |
| 2616 | | void texture_info::prescale() |
| 2617 | | { |
| 2618 | | surface *scale_surface; |
| 2619 | | HRESULT result; |
| 2620 | | int i; |
| 2621 | | |
| 2622 | | // if we don't need to, just skip it |
| 2623 | | if (m_d3dtex == m_d3dfinaltex) |
| 2624 | | return; |
| 2625 | | |
| 2626 | | // for all cases, we need to get the surface of the render target |
| 2627 | | result = (*d3dintf->texture.get_surface_level)(m_d3dfinaltex, 0, &scale_surface); |
| 2628 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during texture get_surface_level call\n", (int)result); |
| 2629 | | |
| 2630 | | // if we have an offscreen plain surface, we can just StretchRect to it |
| 2631 | | if (m_type == TEXTURE_TYPE_SURFACE) |
| 2632 | | { |
| 2633 | | assert(m_d3dsurface != NULL); |
| 2634 | | |
| 2635 | | // set the source bounds |
| 2636 | | RECT source; |
| 2637 | | source.left = source.top = 0; |
| 2638 | | source.right = m_texinfo.width + 2 * m_xborderpix; |
| 2639 | | source.bottom = m_texinfo.height + 2 * m_yborderpix; |
| 2640 | | |
| 2641 | | // set the target bounds |
| 2642 | | RECT dest; |
| 2643 | | dest = source; |
| 2644 | | dest.right *= m_xprescale; |
| 2645 | | dest.bottom *= m_yprescale; |
| 2646 | | |
| 2647 | | // do the stretchrect |
| 2648 | | result = (*d3dintf->device.stretch_rect)(m_renderer->get_device(), m_d3dsurface, &source, scale_surface, &dest, D3DTEXF_POINT); |
| 2649 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device stretct_rect call\n", (int)result); |
| 2650 | | } |
| 2651 | | |
| 2652 | | // if we are using a texture render target, we need to do more preparations |
| 2653 | | else |
| 2654 | | { |
| 2655 | | surface *backbuffer; |
| 2656 | | |
| 2657 | | assert(m_d3dtex != NULL); |
| 2658 | | |
| 2659 | | // first remember the original render target and set the new one |
| 2660 | | result = (*d3dintf->device.get_render_target)(m_renderer->get_device(), 0, &backbuffer); |
| 2661 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device get_render_target call\n", (int)result); |
| 2662 | | result = (*d3dintf->device.set_render_target)(m_renderer->get_device(), 0, scale_surface); |
| 2663 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call 1\n", (int)result); |
| 2664 | | m_renderer->reset_render_states(); |
| 2665 | | |
| 2666 | | // start the scene |
| 2667 | | result = (*d3dintf->device.begin_scene)(m_renderer->get_device()); |
| 2668 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device begin_scene call\n", (int)result); |
| 2669 | | |
| 2670 | | // configure the rendering pipeline |
| 2671 | | m_renderer->set_filter(FALSE); |
| 2672 | | m_renderer->set_blendmode(BLENDMODE_NONE); |
| 2673 | | result = (*d3dintf->device.set_texture)(m_renderer->get_device(), 0, m_d3dtex); |
| 2674 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture call\n", (int)result); |
| 2675 | | |
| 2676 | | // lock the vertex buffer |
| 2677 | | result = (*d3dintf->vertexbuf.lock)(m_renderer->get_vertex_buffer(), 0, 0, m_renderer->get_locked_buffer_ptr(), D3DLOCK_DISCARD); |
| 2678 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during vertex buffer lock call\n", (int)result); |
| 2679 | | |
| 2680 | | // configure the X/Y coordinates on the target surface |
| 2681 | | vertex *lockedbuf = m_renderer->get_locked_buffer(); |
| 2682 | | lockedbuf[0].x = -0.5f; |
| 2683 | | lockedbuf[0].y = -0.5f; |
| 2684 | | lockedbuf[1].x = (float)((m_texinfo.width + 2 * m_xborderpix) * m_xprescale) - 0.5f; |
| 2685 | | lockedbuf[1].y = -0.5f; |
| 2686 | | lockedbuf[2].x = -0.5f; |
| 2687 | | lockedbuf[2].y = (float)((m_texinfo.height + 2 * m_yborderpix) * m_yprescale) - 0.5f; |
| 2688 | | lockedbuf[3].x = (float)((m_texinfo.width + 2 * m_xborderpix) * m_xprescale) - 0.5f; |
| 2689 | | lockedbuf[3].y = (float)((m_texinfo.height + 2 * m_yborderpix) * m_yprescale) - 0.5f; |
| 2690 | | |
| 2691 | | // configure the U/V coordintes on the source texture |
| 2692 | | lockedbuf[0].u0 = 0.0f; |
| 2693 | | lockedbuf[0].v0 = 0.0f; |
| 2694 | | lockedbuf[1].u0 = (float)(m_texinfo.width + 2 * m_xborderpix) / (float)m_rawdims.c.x; |
| 2695 | | lockedbuf[1].v0 = 0.0f; |
| 2696 | | lockedbuf[2].u0 = 0.0f; |
| 2697 | | lockedbuf[2].v0 = (float)(m_texinfo.height + 2 * m_yborderpix) / (float)m_rawdims.c.y; |
| 2698 | | lockedbuf[3].u0 = (float)(m_texinfo.width + 2 * m_xborderpix) / (float)m_rawdims.c.x; |
| 2699 | | lockedbuf[3].v0 = (float)(m_texinfo.height + 2 * m_yborderpix) / (float)m_rawdims.c.y; |
| 2700 | | |
| 2701 | | // reset the remaining vertex parameters |
| 2702 | | for (i = 0; i < 4; i++) |
| 2703 | | { |
| 2704 | | lockedbuf[i].z = 0.0f; |
| 2705 | | lockedbuf[i].rhw = 1.0f; |
| 2706 | | lockedbuf[i].color = D3DCOLOR_ARGB(0xff,0xff,0xff,0xff); |
| 2707 | | } |
| 2708 | | |
| 2709 | | // unlock the vertex buffer |
| 2710 | | result = (*d3dintf->vertexbuf.unlock)(m_renderer->get_vertex_buffer()); |
| 2711 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during vertex buffer unlock call\n", (int)result); |
| 2712 | | m_renderer->set_locked_buffer(NULL); |
| 2713 | | |
| 2714 | | // set the stream and draw the triangle strip |
| 2715 | | result = (*d3dintf->device.set_stream_source)(m_renderer->get_device(), 0, m_renderer->get_vertex_buffer(), sizeof(vertex)); |
| 2716 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_stream_source call\n", (int)result); |
| 2717 | | result = (*d3dintf->device.draw_primitive)(m_renderer->get_device(), D3DPT_TRIANGLESTRIP, 0, 2); |
| 2718 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device draw_primitive call\n", (int)result); |
| 2719 | | |
| 2720 | | // end the scene |
| 2721 | | result = (*d3dintf->device.end_scene)(m_renderer->get_device()); |
| 2722 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device end_scene call\n", (int)result); |
| 2723 | | |
| 2724 | | // reset the render target and release our reference to the backbuffer |
| 2725 | | result = (*d3dintf->device.set_render_target)(m_renderer->get_device(), 0, backbuffer); |
| 2726 | | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call 2\n", (int)result); |
| 2727 | | (*d3dintf->surface.release)(backbuffer); |
| 2728 | | m_renderer->reset_render_states(); |
| 2729 | | } |
| 2730 | | |
| 2731 | | // release our reference to the target surface |
| 2732 | | (*d3dintf->surface.release)(scale_surface); |
| 2733 | | } |
| 2734 | | |
| 2735 | | |
| 2736 | | //============================================================ |
| 2737 | | // cache_target::~cache_target |
| 2738 | | //============================================================ |
| 2739 | | |
| 2740 | | cache_target::~cache_target() |
| 2741 | | { |
| 2742 | | for (int index = 0; index < 11; index++) |
| 2743 | | { |
| 2744 | | if (bloom_texture[index] != NULL) |
| 2745 | | { |
| 2746 | | (*d3dintf->texture.release)(bloom_texture[index]); |
| 2747 | | bloom_texture[index] = NULL; |
| 2748 | | } |
| 2749 | | if (bloom_target[index] != NULL) |
| 2750 | | { |
| 2751 | | (*d3dintf->surface.release)(bloom_target[index]); |
| 2752 | | bloom_target[index] = NULL; |
| 2753 | | } |
| 2754 | | } |
| 2755 | | |
| 2756 | | if (last_texture != NULL) |
| 2757 | | { |
| 2758 | | (*d3dintf->texture.release)(last_texture); |
| 2759 | | last_texture = NULL; |
| 2760 | | } |
| 2761 | | if (last_target != NULL) |
| 2762 | | { |
| 2763 | | (*d3dintf->surface.release)(last_target); |
| 2764 | | last_target = NULL; |
| 2765 | | } |
| 2766 | | } |
| 2767 | | |
| 2768 | | |
| 2769 | | //============================================================ |
| 2770 | | // cache_target::init - initializes a target cache |
| 2771 | | //============================================================ |
| 2772 | | |
| 2773 | | bool cache_target::init(renderer *d3d, base *d3dintf, int width, int height, int prescale_x, int prescale_y) |
| 2774 | | { |
| 2775 | | int bloom_index = 0; |
| 2776 | | int bloom_size = (width < height) ? width : height; |
| 2777 | | int bloom_width = width; |
| 2778 | | int bloom_height = height; |
| 2779 | | for (; bloom_size >= 2 && bloom_index < 11; bloom_size >>= 1) |
| 2780 | | { |
| 2781 | | bloom_width >>= 1; |
| 2782 | | bloom_height >>= 1; |
| 2783 | | |
| 2784 | | HRESULT result = (*d3dintf->device.create_texture)(d3d->get_device(), bloom_width, bloom_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bloom_texture[bloom_index]); |
| 2785 | | if (result != D3D_OK) |
| 2786 | | { |
| 2787 | | return false; |
| 2788 | | } |
| 2789 | | (*d3dintf->texture.get_surface_level)(bloom_texture[bloom_index], 0, &bloom_target[bloom_index]); |
| 2790 | | |
| 2791 | | bloom_index++; |
| 2792 | | } |
| 2793 | | |
| 2794 | | HRESULT result = (*d3dintf->device.create_texture)(d3d->get_device(), width * prescale_x, height * prescale_y, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &last_texture); |
| 2795 | | if (result != D3D_OK) |
| 2796 | | { |
| 2797 | | return false; |
| 2798 | | } |
| 2799 | | (*d3dintf->texture.get_surface_level)(last_texture, 0, &last_target); |
| 2800 | | |
| 2801 | | target_width = width * prescale_x; |
| 2802 | | target_height = height * prescale_y; |
| 2803 | | |
| 2804 | | return true; |
| 2805 | | } |
| 2806 | | |
| 2807 | | |
| 2808 | | //============================================================ |
| 2809 | | // render_target::~render_target |
| 2810 | | //============================================================ |
| 2811 | | |
| 2812 | | render_target::~render_target() |
| 2813 | | { |
| 2814 | | for (int index = 0; index < 11; index++) |
| 2815 | | { |
| 2816 | | if (bloom_texture[index] != NULL) |
| 2817 | | { |
| 2818 | | (*d3dintf->texture.release)(bloom_texture[index]); |
| 2819 | | bloom_texture[index] = NULL; |
| 2820 | | } |
| 2821 | | if (bloom_target[index] != NULL) |
| 2822 | | { |
| 2823 | | (*d3dintf->surface.release)(bloom_target[index]); |
| 2824 | | bloom_target[index] = NULL; |
| 2825 | | } |
| 2826 | | } |
| 2827 | | |
| 2828 | | for (int index = 0; index < 2; index++) |
| 2829 | | { |
| 2830 | | if (native_texture[index] != NULL) |
| 2831 | | { |
| 2832 | | (*d3dintf->texture.release)(native_texture[index]); |
| 2833 | | native_texture[index] = NULL; |
| 2834 | | } |
| 2835 | | if (native_target[index] != NULL) |
| 2836 | | { |
| 2837 | | (*d3dintf->surface.release)(native_target[index]); |
| 2838 | | native_target[index] = NULL; |
| 2839 | | } |
| 2840 | | if (prescale_texture[index] != NULL) |
| 2841 | | { |
| 2842 | | (*d3dintf->texture.release)(prescale_texture[index]); |
| 2843 | | prescale_texture[index] = NULL; |
| 2844 | | } |
| 2845 | | if (prescale_target[index] != NULL) |
| 2846 | | { |
| 2847 | | (*d3dintf->surface.release)(prescale_target[index]); |
| 2848 | | prescale_target[index] = NULL; |
| 2849 | | } |
| 2850 | | } |
| 2851 | | } |
| 2852 | | |
| 2853 | | |
| 2854 | | //============================================================ |
| 2855 | | // render_target::init - initializes a render target |
| 2856 | | //============================================================ |
| 2857 | | |
| 2858 | | bool render_target::init(renderer *d3d, base *d3dintf, int width, int height, int prescale_x, int prescale_y) |
| 2859 | | { |
| 2860 | | HRESULT result; |
| 2861 | | |
| 2862 | | for (int index = 0; index < 2; index++) |
| 2863 | | { |
| 2864 | | result = (*d3dintf->device.create_texture)(d3d->get_device(), width, height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &native_texture[index]); |
| 2865 | | if (result != D3D_OK) |
| 2866 | | { |
| 2867 | | return false; |
| 2868 | | } |
| 2869 | | (*d3dintf->texture.get_surface_level)(native_texture[index], 0, &native_target[index]); |
| 2870 | | |
| 2871 | | result = (*d3dintf->device.create_texture)(d3d->get_device(), width * prescale_x, height * prescale_y, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &prescale_texture[index]); |
| 2872 | | if (result != D3D_OK) |
| 2873 | | { |
| 2874 | | return false; |
| 2875 | | } |
| 2876 | | (*d3dintf->texture.get_surface_level)(prescale_texture[index], 0, &prescale_target[index]); |
| 2877 | | } |
| 2878 | | |
| 2879 | | int bloom_index = 0; |
| 2880 | | float bloom_size = (d3d->get_width() < d3d->get_height()) ? d3d->get_width() : d3d->get_height(); |
| 2881 | | float bloom_width = d3d->get_width(); |
| 2882 | | float bloom_height = d3d->get_height(); |
| 2883 | | for (; bloom_size >= 2.0f && bloom_index < 11; bloom_size *= 0.5f) |
| 2884 | | { |
| 2885 | | bloom_width *= 0.5f; |
| 2886 | | bloom_height *= 0.5f; |
| 2887 | | |
| 2888 | | result = (*d3dintf->device.create_texture)(d3d->get_device(), (int)bloom_width, (int)bloom_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bloom_texture[bloom_index]); |
| 2889 | | if (result != D3D_OK) |
| 2890 | | { |
| 2891 | | return false; |
| 2892 | | } |
| 2893 | | (*d3dintf->texture.get_surface_level)(bloom_texture[bloom_index], 0, &bloom_target[bloom_index]); |
| 2894 | | |
| 2895 | | bloom_index++; |
| 2896 | | } |
| 2897 | | |
| 2898 | | this->width = width; |
| 2899 | | this->height = height; |
| 2900 | | |
| 2901 | | target_width = width * prescale_x; |
| 2902 | | target_height = height * prescale_y; |
| 2903 | | |
| 2904 | | return true; |
| 2905 | | } |
| 2906 | | |
| 2907 | | } |
trunk/src/osd/modules/render/drawd3d.cpp
| r0 | r250288 | |
| 1 | // license:BSD-3-Clause |
| 2 | // copyright-holders:Aaron Giles |
| 3 | //============================================================ |
| 4 | // |
| 5 | // drawd3d.c - Win32 Direct3D implementation |
| 6 | // |
| 7 | //============================================================ |
| 8 | |
| 9 | // Useful info: |
| 10 | // Windows XP/2003 shipped with DirectX 8.1 |
| 11 | // Windows 2000 shipped with DirectX 7a |
| 12 | // Windows 98SE shipped with DirectX 6.1a |
| 13 | // Windows 98 shipped with DirectX 5 |
| 14 | // Windows NT shipped with DirectX 3.0a |
| 15 | // Windows 95 shipped with DirectX 2 |
| 16 | |
| 17 | // standard windows headers |
| 18 | #define WIN32_LEAN_AND_MEAN |
| 19 | #include <windows.h> |
| 20 | #include <tchar.h> |
| 21 | #include <mmsystem.h> |
| 22 | #include <d3d9.h> |
| 23 | #include <d3dx9.h> |
| 24 | #include <math.h> |
| 25 | #undef interface |
| 26 | |
| 27 | // MAME headers |
| 28 | #include "emu.h" |
| 29 | #include "render.h" |
| 30 | #include "ui/ui.h" |
| 31 | #include "rendutil.h" |
| 32 | #include "options.h" |
| 33 | #include "emuopts.h" |
| 34 | #include "aviio.h" |
| 35 | #include "png.h" |
| 36 | |
| 37 | // MAMEOS headers |
| 38 | #include "modules/render/d3d/d3dintf.h" |
| 39 | #include "winmain.h" |
| 40 | #include "window.h" |
| 41 | #include "config.h" |
| 42 | #include "strconv.h" |
| 43 | #include "modules/render/d3d/d3dcomm.h" |
| 44 | #include "drawd3d.h" |
| 45 | |
| 46 | |
| 47 | //============================================================ |
| 48 | // DEBUGGING |
| 49 | //============================================================ |
| 50 | |
| 51 | extern void mtlog_add(const char *event); |
| 52 | |
| 53 | |
| 54 | //============================================================ |
| 55 | // CONSTANTS |
| 56 | //============================================================ |
| 57 | |
| 58 | #define ENABLE_BORDER_PIX (1) |
| 59 | |
| 60 | enum |
| 61 | { |
| 62 | TEXTURE_TYPE_PLAIN, |
| 63 | TEXTURE_TYPE_DYNAMIC, |
| 64 | TEXTURE_TYPE_SURFACE |
| 65 | }; |
| 66 | |
| 67 | |
| 68 | //============================================================ |
| 69 | // MACROS |
| 70 | //============================================================ |
| 71 | |
| 72 | #define FSWAP(var1, var2) do { float temp = var1; var1 = var2; var2 = temp; } while (0) |
| 73 | |
| 74 | |
| 75 | //============================================================ |
| 76 | // GLOBALS |
| 77 | //============================================================ |
| 78 | |
| 79 | static const line_aa_step line_aa_1step[] = |
| 80 | { |
| 81 | { 0.00f, 0.00f, 1.00f }, |
| 82 | { 0 } |
| 83 | }; |
| 84 | |
| 85 | static const line_aa_step line_aa_4step[] = |
| 86 | { |
| 87 | { -0.25f, 0.00f, 0.25f }, |
| 88 | { 0.25f, 0.00f, 0.25f }, |
| 89 | { 0.00f, -0.25f, 0.25f }, |
| 90 | { 0.00f, 0.25f, 0.25f }, |
| 91 | { 0 } |
| 92 | }; |
| 93 | |
| 94 | |
| 95 | //============================================================ |
| 96 | // INLINES |
| 97 | //============================================================ |
| 98 | |
| 99 | INLINE BOOL GetClientRectExceptMenu(HWND hWnd, PRECT pRect, BOOL fullscreen) |
| 100 | { |
| 101 | static HMENU last_menu; |
| 102 | static RECT last_rect; |
| 103 | static RECT cached_rect; |
| 104 | HMENU menu = GetMenu(hWnd); |
| 105 | BOOL result = GetClientRect(hWnd, pRect); |
| 106 | |
| 107 | if (!fullscreen || !menu) |
| 108 | return result; |
| 109 | |
| 110 | // to avoid flicker use cache if we can use |
| 111 | if (last_menu != menu || memcmp(&last_rect, pRect, sizeof *pRect) != 0) |
| 112 | { |
| 113 | last_menu = menu; |
| 114 | last_rect = *pRect; |
| 115 | |
| 116 | SetMenu(hWnd, NULL); |
| 117 | result = GetClientRect(hWnd, &cached_rect); |
| 118 | SetMenu(hWnd, menu); |
| 119 | } |
| 120 | |
| 121 | *pRect = cached_rect; |
| 122 | return result; |
| 123 | } |
| 124 | |
| 125 | |
| 126 | INLINE UINT32 ycc_to_rgb(UINT8 y, UINT8 cb, UINT8 cr) |
| 127 | { |
| 128 | /* original equations: |
| 129 | |
| 130 | C = Y - 16 |
| 131 | D = Cb - 128 |
| 132 | E = Cr - 128 |
| 133 | |
| 134 | R = clip(( 298 * C + 409 * E + 128) >> 8) |
| 135 | G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8) |
| 136 | B = clip(( 298 * C + 516 * D + 128) >> 8) |
| 137 | |
| 138 | R = clip(( 298 * (Y - 16) + 409 * (Cr - 128) + 128) >> 8) |
| 139 | G = clip(( 298 * (Y - 16) - 100 * (Cb - 128) - 208 * (Cr - 128) + 128) >> 8) |
| 140 | B = clip(( 298 * (Y - 16) + 516 * (Cb - 128) + 128) >> 8) |
| 141 | |
| 142 | R = clip(( 298 * Y - 298 * 16 + 409 * Cr - 409 * 128 + 128) >> 8) |
| 143 | G = clip(( 298 * Y - 298 * 16 - 100 * Cb + 100 * 128 - 208 * Cr + 208 * 128 + 128) >> 8) |
| 144 | B = clip(( 298 * Y - 298 * 16 + 516 * Cb - 516 * 128 + 128) >> 8) |
| 145 | |
| 146 | R = clip(( 298 * Y - 298 * 16 + 409 * Cr - 409 * 128 + 128) >> 8) |
| 147 | G = clip(( 298 * Y - 298 * 16 - 100 * Cb + 100 * 128 - 208 * Cr + 208 * 128 + 128) >> 8) |
| 148 | B = clip(( 298 * Y - 298 * 16 + 516 * Cb - 516 * 128 + 128) >> 8) |
| 149 | */ |
| 150 | int r, g, b, common; |
| 151 | |
| 152 | common = 298 * y - 298 * 16; |
| 153 | r = (common + 409 * cr - 409 * 128 + 128) >> 8; |
| 154 | g = (common - 100 * cb + 100 * 128 - 208 * cr + 208 * 128 + 128) >> 8; |
| 155 | b = (common + 516 * cb - 516 * 128 + 128) >> 8; |
| 156 | |
| 157 | if (r < 0) r = 0; |
| 158 | else if (r > 255) r = 255; |
| 159 | if (g < 0) g = 0; |
| 160 | else if (g > 255) g = 255; |
| 161 | if (b < 0) b = 0; |
| 162 | else if (b > 255) b = 255; |
| 163 | |
| 164 | return rgb_t(0xff, r, g, b); |
| 165 | } |
| 166 | |
| 167 | |
| 168 | //============================================================ |
| 169 | // drawd3d_init |
| 170 | //============================================================ |
| 171 | |
| 172 | static d3d::base * d3dintf; // FIX ME |
| 173 | |
| 174 | |
| 175 | //============================================================ |
| 176 | // PROTOTYPES |
| 177 | //============================================================ |
| 178 | |
| 179 | // core functions |
| 180 | static void drawd3d_exit(void); |
| 181 | |
| 182 | |
| 183 | //============================================================ |
| 184 | // drawd3d_window_init |
| 185 | //============================================================ |
| 186 | |
| 187 | int d3d::renderer::create() |
| 188 | { |
| 189 | if (!initialize()) |
| 190 | { |
| 191 | destroy(); |
| 192 | osd_printf_error("Unable to initialize Direct3D.\n"); |
| 193 | return 1; |
| 194 | } |
| 195 | |
| 196 | return 0; |
| 197 | } |
| 198 | |
| 199 | |
| 200 | //============================================================ |
| 201 | // drawd3d_exit |
| 202 | //============================================================ |
| 203 | |
| 204 | static void drawd3d_exit(void) |
| 205 | { |
| 206 | if (d3dintf != NULL) |
| 207 | (*d3dintf->d3d.release)(d3dintf); |
| 208 | } |
| 209 | |
| 210 | void d3d::renderer::toggle_fsfx() |
| 211 | { |
| 212 | set_restarting(true); |
| 213 | } |
| 214 | |
| 215 | void d3d::renderer::record() |
| 216 | { |
| 217 | get_shaders()->window_record(); |
| 218 | } |
| 219 | |
| 220 | void d3d::renderer::save() |
| 221 | { |
| 222 | get_shaders()->window_save(); |
| 223 | } |
| 224 | |
| 225 | |
| 226 | //============================================================ |
| 227 | // drawd3d_window_destroy |
| 228 | //============================================================ |
| 229 | |
| 230 | void d3d::renderer::destroy() |
| 231 | { |
| 232 | if (get_shaders() != NULL && get_shaders()->recording()) |
| 233 | get_shaders()->window_record(); |
| 234 | |
| 235 | } |
| 236 | |
| 237 | |
| 238 | //============================================================ |
| 239 | // drawd3d_window_get_primitives |
| 240 | //============================================================ |
| 241 | |
| 242 | render_primitive_list *d3d::renderer::get_primitives() |
| 243 | { |
| 244 | RECT client; |
| 245 | |
| 246 | GetClientRectExceptMenu(window().m_hwnd, &client, window().fullscreen()); |
| 247 | if (rect_width(&client) > 0 && rect_height(&client) > 0) |
| 248 | { |
| 249 | window().target()->set_bounds(rect_width(&client), rect_height(&client), window().aspect()); |
| 250 | window().target()->set_max_update_rate((get_refresh() == 0) ? get_origmode().RefreshRate : get_refresh()); |
| 251 | } |
| 252 | return &window().target()->get_primitives(); |
| 253 | } |
| 254 | |
| 255 | |
| 256 | //============================================================ |
| 257 | // drawnone_create |
| 258 | //============================================================ |
| 259 | |
| 260 | static osd_renderer *drawd3d_create(osd_window *window) |
| 261 | { |
| 262 | return global_alloc(d3d::renderer(window)); |
| 263 | } |
| 264 | |
| 265 | int drawd3d_init(running_machine &machine, osd_draw_callbacks *callbacks) |
| 266 | { |
| 267 | d3dintf = NULL; |
| 268 | |
| 269 | // Use Direct3D9 |
| 270 | d3dintf = d3d::drawd3d9_init(); |
| 271 | |
| 272 | // if we failed, note the error |
| 273 | if (d3dintf == NULL) |
| 274 | { |
| 275 | osd_printf_error("Unable to initialize Direct3D.\n"); |
| 276 | return 1; |
| 277 | } |
| 278 | |
| 279 | // fill in the callbacks |
| 280 | memset(callbacks, 0, sizeof(*callbacks)); |
| 281 | callbacks->exit = drawd3d_exit; |
| 282 | callbacks->create = drawd3d_create; |
| 283 | return 0; |
| 284 | } |
| 285 | |
| 286 | |
| 287 | //============================================================ |
| 288 | // drawd3d_window_draw |
| 289 | //============================================================ |
| 290 | |
| 291 | int d3d::renderer::draw(const int update) |
| 292 | { |
| 293 | int check = pre_window_draw_check(); |
| 294 | if (check >= 0) |
| 295 | return check; |
| 296 | |
| 297 | begin_frame(); |
| 298 | process_primitives(); |
| 299 | end_frame(); |
| 300 | |
| 301 | return 0; |
| 302 | } |
| 303 | |
| 304 | namespace d3d |
| 305 | { |
| 306 | void renderer::set_texture(texture_info *texture) |
| 307 | { |
| 308 | if (texture != m_last_texture) |
| 309 | { |
| 310 | m_last_texture = texture; |
| 311 | m_last_texture_flags = (texture == NULL ? 0 : texture->get_flags()); |
| 312 | HRESULT result = (*d3dintf->device.set_texture)(m_device, 0, (texture == NULL) ? get_default_texture()->get_finaltex() : texture->get_finaltex()); |
| 313 | m_shaders->set_texture(texture); |
| 314 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture call\n", (int)result); |
| 315 | } |
| 316 | } |
| 317 | |
| 318 | void renderer::set_filter(int filter) |
| 319 | { |
| 320 | if (filter != m_last_filter) |
| 321 | { |
| 322 | m_last_filter = filter; |
| 323 | HRESULT result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MINFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT); |
| 324 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result); |
| 325 | result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MAGFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT); |
| 326 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result); |
| 327 | result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MINFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT); |
| 328 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result); |
| 329 | result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, (D3DTEXTURESTAGESTATETYPE)D3DTSS_MAGFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT); |
| 330 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result); |
| 331 | } |
| 332 | } |
| 333 | |
| 334 | void renderer::set_wrap(D3DTEXTUREADDRESS wrap) |
| 335 | { |
| 336 | if (wrap != m_last_wrap) |
| 337 | { |
| 338 | m_last_wrap = wrap; |
| 339 | HRESULT result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSU, wrap); |
| 340 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result); |
| 341 | result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSV, wrap); |
| 342 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result); |
| 343 | result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSU, wrap); |
| 344 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result); |
| 345 | result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, (D3DTEXTURESTAGESTATETYPE)D3DTSS_ADDRESSV, wrap); |
| 346 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result); |
| 347 | } |
| 348 | } |
| 349 | |
| 350 | void renderer::set_modmode(DWORD modmode) |
| 351 | { |
| 352 | if (modmode != m_last_modmode) |
| 353 | { |
| 354 | m_last_modmode = modmode; |
| 355 | HRESULT result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, D3DTSS_COLOROP, modmode); |
| 356 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result); |
| 357 | result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, D3DTSS_COLOROP, modmode); |
| 358 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture_stage_state call\n", (int)result); |
| 359 | } |
| 360 | } |
| 361 | |
| 362 | void renderer::set_blendmode(int blendmode) |
| 363 | { |
| 364 | int blendenable; |
| 365 | int blendop; |
| 366 | int blendsrc; |
| 367 | int blenddst; |
| 368 | |
| 369 | // choose the parameters |
| 370 | switch (blendmode) |
| 371 | { |
| 372 | default: |
| 373 | case BLENDMODE_NONE: blendenable = FALSE; blendop = D3DBLENDOP_ADD; blendsrc = D3DBLEND_SRCALPHA; blenddst = D3DBLEND_INVSRCALPHA; break; |
| 374 | case BLENDMODE_ALPHA: blendenable = TRUE; blendop = D3DBLENDOP_ADD; blendsrc = D3DBLEND_SRCALPHA; blenddst = D3DBLEND_INVSRCALPHA; break; |
| 375 | case BLENDMODE_RGB_MULTIPLY: blendenable = TRUE; blendop = D3DBLENDOP_ADD; blendsrc = D3DBLEND_DESTCOLOR; blenddst = D3DBLEND_ZERO; break; |
| 376 | case BLENDMODE_ADD: blendenable = TRUE; blendop = D3DBLENDOP_ADD; blendsrc = D3DBLEND_SRCALPHA; blenddst = D3DBLEND_ONE; break; |
| 377 | } |
| 378 | |
| 379 | // adjust the bits that changed |
| 380 | if (blendenable != m_last_blendenable) |
| 381 | { |
| 382 | m_last_blendenable = blendenable; |
| 383 | HRESULT result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ALPHABLENDENABLE, blendenable); |
| 384 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_state call\n", (int)result); |
| 385 | } |
| 386 | |
| 387 | if (blendop != m_last_blendop) |
| 388 | { |
| 389 | m_last_blendop = blendop; |
| 390 | HRESULT result = (*d3dintf->device.set_render_state)(m_device, D3DRS_BLENDOP, blendop); |
| 391 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_state call\n", (int)result); |
| 392 | } |
| 393 | |
| 394 | if (blendsrc != m_last_blendsrc) |
| 395 | { |
| 396 | m_last_blendsrc = blendsrc; |
| 397 | HRESULT result = (*d3dintf->device.set_render_state)(m_device, D3DRS_SRCBLEND, blendsrc); |
| 398 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_state call\n", (int)result); |
| 399 | } |
| 400 | |
| 401 | if (blenddst != m_last_blenddst) |
| 402 | { |
| 403 | m_last_blenddst = blenddst; |
| 404 | HRESULT result = (*d3dintf->device.set_render_state)(m_device, D3DRS_DESTBLEND, blenddst); |
| 405 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_state call\n", (int)result); |
| 406 | } |
| 407 | } |
| 408 | |
| 409 | void renderer::reset_render_states() |
| 410 | { |
| 411 | // this ensures subsequent calls to the above setters will force-update the data |
| 412 | m_last_texture = (texture_info *)~0; |
| 413 | m_last_filter = -1; |
| 414 | m_last_blendenable = -1; |
| 415 | m_last_blendop = -1; |
| 416 | m_last_blendsrc = -1; |
| 417 | m_last_blenddst = -1; |
| 418 | m_last_wrap = (D3DTEXTUREADDRESS)-1; |
| 419 | } |
| 420 | |
| 421 | texture_manager::texture_manager(renderer *d3d) |
| 422 | { |
| 423 | m_renderer = d3d; |
| 424 | |
| 425 | m_texlist = NULL; |
| 426 | m_vector_texture = NULL; |
| 427 | m_default_texture = NULL; |
| 428 | |
| 429 | // check for dynamic texture support |
| 430 | DWORD tempcaps; |
| 431 | HRESULT result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_CAPS2, &tempcaps); |
| 432 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result); |
| 433 | m_dynamic_supported = ((tempcaps & D3DCAPS2_DYNAMICTEXTURES) != 0); |
| 434 | if (m_dynamic_supported) osd_printf_verbose("Direct3D: Using dynamic textures\n"); |
| 435 | |
| 436 | // check for stretchrect support |
| 437 | result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_STRETCH_RECT_FILTER, &tempcaps); |
| 438 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result); |
| 439 | m_stretch_supported = ((tempcaps & D3DPTFILTERCAPS_MAGFPOINT) != 0); |
| 440 | if (m_stretch_supported && video_config.prescale > 1) osd_printf_verbose("Direct3D: Using StretchRect for prescaling\n"); |
| 441 | |
| 442 | // get texture caps |
| 443 | result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_TEXTURE_CAPS, &m_texture_caps); |
| 444 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result); |
| 445 | result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_MAX_TEXTURE_ASPECT, &m_texture_max_aspect); |
| 446 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result); |
| 447 | result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_MAX_TEXTURE_WIDTH, &m_texture_max_width); |
| 448 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result); |
| 449 | result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, CAPS_MAX_TEXTURE_HEIGHT, &m_texture_max_height); |
| 450 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result); |
| 451 | |
| 452 | // pick a YUV texture format |
| 453 | m_yuv_format = D3DFMT_UYVY; |
| 454 | result = (*d3dintf->d3d.check_device_format)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, d3d->get_pixel_format(), 0, D3DRTYPE_TEXTURE, D3DFMT_UYVY); |
| 455 | if (result != D3D_OK) |
| 456 | { |
| 457 | m_yuv_format = D3DFMT_YUY2; |
| 458 | result = (*d3dintf->d3d.check_device_format)(d3dintf, d3d->get_adapter(), D3DDEVTYPE_HAL, d3d->get_pixel_format(), 0, D3DRTYPE_TEXTURE, D3DFMT_YUY2); |
| 459 | if (result != D3D_OK) |
| 460 | m_yuv_format = D3DFMT_A8R8G8B8; |
| 461 | } |
| 462 | osd_printf_verbose("Direct3D: YUV format = %s\n", (m_yuv_format == D3DFMT_YUY2) ? "YUY2" : (m_yuv_format == D3DFMT_UYVY) ? "UYVY" : "RGB"); |
| 463 | |
| 464 | // set the max texture size |
| 465 | d3d->window().target()->set_max_texture_size(m_texture_max_width, m_texture_max_height); |
| 466 | osd_printf_verbose("Direct3D: Max texture size = %dx%d\n", (int)m_texture_max_width, (int)m_texture_max_height); |
| 467 | } |
| 468 | |
| 469 | texture_manager::~texture_manager() |
| 470 | { |
| 471 | } |
| 472 | |
| 473 | void texture_manager::create_resources() |
| 474 | { |
| 475 | // experimental: load a PNG to use for vector rendering; it is treated |
| 476 | // as a brightness map |
| 477 | emu_file file(m_renderer->window().machine().options().art_path(), OPEN_FLAG_READ); |
| 478 | render_load_png(m_vector_bitmap, file, NULL, "vector.png"); |
| 479 | if (m_vector_bitmap.valid()) |
| 480 | { |
| 481 | m_vector_bitmap.fill(rgb_t(0xff,0xff,0xff,0xff)); |
| 482 | render_load_png(m_vector_bitmap, file, NULL, "vector.png", true); |
| 483 | } |
| 484 | |
| 485 | m_default_bitmap.allocate(8, 8); |
| 486 | m_default_bitmap.fill(rgb_t(0xff,0xff,0xff,0xff)); |
| 487 | |
| 488 | if (m_default_bitmap.valid()) |
| 489 | { |
| 490 | render_texinfo texture; |
| 491 | |
| 492 | // fake in the basic data so it looks like it came from render.c |
| 493 | texture.base = m_default_bitmap.raw_pixptr(0); |
| 494 | texture.rowpixels = m_default_bitmap.rowpixels(); |
| 495 | texture.width = m_default_bitmap.width(); |
| 496 | texture.height = m_default_bitmap.height(); |
| 497 | texture.palette = NULL; |
| 498 | texture.seqid = 0; |
| 499 | |
| 500 | // now create it |
| 501 | m_default_texture = global_alloc(texture_info(this, &texture, m_renderer->window().prescale(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32))); |
| 502 | } |
| 503 | |
| 504 | // experimental: if we have a vector bitmap, create a texture for it |
| 505 | if (m_vector_bitmap.valid()) |
| 506 | { |
| 507 | render_texinfo texture; |
| 508 | |
| 509 | // fake in the basic data so it looks like it came from render.c |
| 510 | texture.base = &m_vector_bitmap.pix32(0); |
| 511 | texture.rowpixels = m_vector_bitmap.rowpixels(); |
| 512 | texture.width = m_vector_bitmap.width(); |
| 513 | texture.height = m_vector_bitmap.height(); |
| 514 | texture.palette = NULL; |
| 515 | texture.seqid = 0; |
| 516 | |
| 517 | // now create it |
| 518 | m_vector_texture = global_alloc(texture_info(this, &texture, m_renderer->window().prescale(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32))); |
| 519 | } |
| 520 | } |
| 521 | |
| 522 | void texture_manager::delete_resources() |
| 523 | { |
| 524 | // is part of m_texlist and will be free'd there |
| 525 | //global_free(m_default_texture); |
| 526 | m_default_texture = NULL; |
| 527 | |
| 528 | //global_free(m_vector_texture); |
| 529 | m_vector_texture = NULL; |
| 530 | |
| 531 | // free all textures |
| 532 | while (m_texlist != NULL) |
| 533 | { |
| 534 | texture_info *tex = m_texlist; |
| 535 | m_texlist = tex->get_next(); |
| 536 | global_free(tex); |
| 537 | } |
| 538 | } |
| 539 | |
| 540 | UINT32 texture_manager::texture_compute_hash(const render_texinfo *texture, UINT32 flags) |
| 541 | { |
| 542 | return (FPTR)texture->base ^ (flags & (PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)); |
| 543 | } |
| 544 | |
| 545 | texture_info *texture_manager::find_texinfo(const render_texinfo *texinfo, UINT32 flags) |
| 546 | { |
| 547 | UINT32 hash = texture_compute_hash(texinfo, flags); |
| 548 | texture_info *texture; |
| 549 | |
| 550 | // find a match |
| 551 | for (texture = m_renderer->get_texture_manager()->get_texlist(); texture != NULL; texture = texture->get_next()) |
| 552 | { |
| 553 | UINT32 test_screen = (UINT32)texture->get_texinfo().osddata >> 1; |
| 554 | UINT32 test_page = (UINT32)texture->get_texinfo().osddata & 1; |
| 555 | UINT32 prim_screen = (UINT32)texinfo->osddata >> 1; |
| 556 | UINT32 prim_page = (UINT32)texinfo->osddata & 1; |
| 557 | if (test_screen != prim_screen || test_page != prim_page) |
| 558 | { |
| 559 | continue; |
| 560 | } |
| 561 | |
| 562 | if (texture->get_hash() == hash && |
| 563 | texture->get_texinfo().base == texinfo->base && |
| 564 | texture->get_texinfo().width == texinfo->width && |
| 565 | texture->get_texinfo().height == texinfo->height && |
| 566 | ((texture->get_flags() ^ flags) & (PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)) == 0) |
| 567 | { |
| 568 | // Reject a texture if it belongs to an out-of-date render target, so as to cause the HLSL system to re-cache |
| 569 | if (m_renderer->get_shaders()->enabled() && texinfo->width != 0 && texinfo->height != 0 && (flags & PRIMFLAG_SCREENTEX_MASK) != 0) |
| 570 | { |
| 571 | if (m_renderer->get_shaders()->find_render_target(texture) != NULL) |
| 572 | { |
| 573 | return texture; |
| 574 | } |
| 575 | } |
| 576 | else |
| 577 | { |
| 578 | return texture; |
| 579 | } |
| 580 | } |
| 581 | } |
| 582 | |
| 583 | // Nothing found, check if we need to unregister something with HLSL |
| 584 | if (m_renderer->get_shaders()->enabled()) |
| 585 | { |
| 586 | if (texinfo->width == 0 || texinfo->height == 0) |
| 587 | { |
| 588 | return NULL; |
| 589 | } |
| 590 | |
| 591 | UINT32 prim_screen = texinfo->osddata >> 1; |
| 592 | UINT32 prim_page = texinfo->osddata & 1; |
| 593 | |
| 594 | for (texture = m_renderer->get_texture_manager()->get_texlist(); texture != NULL; texture = texture->get_next()) |
| 595 | { |
| 596 | UINT32 test_screen = texture->get_texinfo().osddata >> 1; |
| 597 | UINT32 test_page = texture->get_texinfo().osddata & 1; |
| 598 | if (test_screen != prim_screen || test_page != prim_page) |
| 599 | { |
| 600 | continue; |
| 601 | } |
| 602 | |
| 603 | // Clear out our old texture reference |
| 604 | if (texture->get_hash() == hash && |
| 605 | texture->get_texinfo().base == texinfo->base && |
| 606 | ((texture->get_flags() ^ flags) & (PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)) == 0 && |
| 607 | (texture->get_texinfo().width != texinfo->width || |
| 608 | texture->get_texinfo().height != texinfo->height)) |
| 609 | { |
| 610 | m_renderer->get_shaders()->remove_render_target(texture); |
| 611 | } |
| 612 | } |
| 613 | } |
| 614 | |
| 615 | return NULL; |
| 616 | } |
| 617 | |
| 618 | renderer::renderer(osd_window *window) |
| 619 | : osd_renderer(window, FLAG_NONE) |
| 620 | { |
| 621 | m_device = NULL; |
| 622 | m_restarting = false; |
| 623 | m_shaders = NULL; |
| 624 | m_numverts = 0; |
| 625 | m_numpolys = 0; |
| 626 | m_vertexbuf = NULL; |
| 627 | m_lockedbuf = NULL; |
| 628 | m_vectorbatch = NULL; |
| 629 | m_last_texture = NULL; |
| 630 | m_hlsl_buf = NULL; |
| 631 | m_texture_manager = NULL; |
| 632 | } |
| 633 | |
| 634 | int renderer::initialize() |
| 635 | { |
| 636 | // configure the adapter for the mode we want |
| 637 | if (config_adapter_mode()) |
| 638 | return false; |
| 639 | |
| 640 | // create the device immediately for the full screen case (defer for window mode) |
| 641 | if (window().fullscreen() && device_create(window().m_focus_hwnd)) |
| 642 | return false; |
| 643 | |
| 644 | return true; |
| 645 | } |
| 646 | |
| 647 | int renderer::pre_window_draw_check() |
| 648 | { |
| 649 | // if we're in the middle of resizing, leave things alone |
| 650 | if (window().m_resize_state == RESIZE_STATE_RESIZING) |
| 651 | return 0; |
| 652 | |
| 653 | // if we're restarting the renderer, leave things alone |
| 654 | if (m_restarting) |
| 655 | { |
| 656 | m_shaders->toggle(); |
| 657 | |
| 658 | // free all existing resources and re-create |
| 659 | device_delete_resources(); |
| 660 | device_create_resources(); |
| 661 | |
| 662 | m_restarting = false; |
| 663 | } |
| 664 | |
| 665 | // if we have a device, check the cooperative level |
| 666 | if (m_device != NULL) |
| 667 | { |
| 668 | if (device_test_cooperative()) |
| 669 | { |
| 670 | return 1; |
| 671 | } |
| 672 | } |
| 673 | |
| 674 | // in window mode, we need to track the window size |
| 675 | if (!window().fullscreen() || m_device == NULL) |
| 676 | { |
| 677 | // if the size changes, skip this update since the render target will be out of date |
| 678 | if (update_window_size()) |
| 679 | return 0; |
| 680 | |
| 681 | // if we have no device, after updating the size, return an error so GDI can try |
| 682 | if (m_device == NULL) |
| 683 | return 1; |
| 684 | } |
| 685 | |
| 686 | return -1; |
| 687 | } |
| 688 | |
| 689 | void texture_manager::update_textures() |
| 690 | { |
| 691 | for (render_primitive *prim = m_renderer->window().m_primlist->first(); prim != NULL; prim = prim->next()) |
| 692 | { |
| 693 | if (prim->texture.base != NULL) |
| 694 | { |
| 695 | texture_info *texture = find_texinfo(&prim->texture, prim->flags); |
| 696 | if (texture == NULL) |
| 697 | { |
| 698 | // if there isn't one, create a new texture |
| 699 | global_alloc(texture_info(this, &prim->texture, m_renderer->window().prescale(), prim->flags)); |
| 700 | } |
| 701 | else |
| 702 | { |
| 703 | // if there is one, but with a different seqid, copy the data |
| 704 | if (texture->get_texinfo().seqid != prim->texture.seqid) |
| 705 | { |
| 706 | texture->set_data(&prim->texture, prim->flags); |
| 707 | texture->get_texinfo().seqid = prim->texture.seqid; |
| 708 | } |
| 709 | } |
| 710 | } |
| 711 | else if(m_renderer->get_shaders()->vector_enabled() && PRIMFLAG_GET_VECTORBUF(prim->flags)) |
| 712 | { |
| 713 | if (!m_renderer->get_shaders()->get_vector_target()) |
| 714 | { |
| 715 | m_renderer->get_shaders()->create_vector_target(prim); |
| 716 | } |
| 717 | } |
| 718 | } |
| 719 | } |
| 720 | |
| 721 | void renderer::begin_frame() |
| 722 | { |
| 723 | HRESULT result = (*d3dintf->device.clear)(m_device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); |
| 724 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result); |
| 725 | |
| 726 | m_shaders->begin_frame(); |
| 727 | |
| 728 | window().m_primlist->acquire_lock(); |
| 729 | |
| 730 | // first update any textures |
| 731 | m_texture_manager->update_textures(); |
| 732 | |
| 733 | // begin the scene |
| 734 | mtlog_add("drawd3d_window_draw: begin_scene"); |
| 735 | result = (*d3dintf->device.begin_scene)(m_device); |
| 736 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device begin_scene call\n", (int)result); |
| 737 | |
| 738 | m_lockedbuf = NULL; |
| 739 | |
| 740 | if(m_shaders->enabled()) |
| 741 | { |
| 742 | m_hlsl_buf = (void*)mesh_alloc(6); |
| 743 | m_shaders->init_fsfx_quad(m_hlsl_buf); |
| 744 | } |
| 745 | |
| 746 | m_line_count = 0; |
| 747 | |
| 748 | // loop over primitives |
| 749 | for (render_primitive *prim = window().m_primlist->first(); prim != NULL; prim = prim->next()) |
| 750 | if (prim->type == render_primitive::LINE && PRIMFLAG_GET_VECTOR(prim->flags)) |
| 751 | m_line_count++; |
| 752 | } |
| 753 | |
| 754 | void renderer::process_primitives() |
| 755 | { |
| 756 | // Rotating index for vector time offsets |
| 757 | for (render_primitive *prim = window().m_primlist->first(); prim != NULL; prim = prim->next()) |
| 758 | { |
| 759 | switch (prim->type) |
| 760 | { |
| 761 | case render_primitive::LINE: |
| 762 | if (PRIMFLAG_GET_VECTOR(prim->flags)) |
| 763 | { |
| 764 | if (m_line_count > 0) |
| 765 | batch_vectors(); |
| 766 | else |
| 767 | continue; |
| 768 | } |
| 769 | else |
| 770 | { |
| 771 | draw_line(prim); |
| 772 | } |
| 773 | break; |
| 774 | |
| 775 | case render_primitive::QUAD: |
| 776 | draw_quad(prim); |
| 777 | break; |
| 778 | |
| 779 | default: |
| 780 | throw emu_fatalerror("Unexpected render_primitive type"); |
| 781 | } |
| 782 | } |
| 783 | } |
| 784 | |
| 785 | void renderer::end_frame() |
| 786 | { |
| 787 | window().m_primlist->release_lock(); |
| 788 | |
| 789 | // flush any pending polygons |
| 790 | primitive_flush_pending(); |
| 791 | |
| 792 | m_shaders->end_frame(); |
| 793 | |
| 794 | // finish the scene |
| 795 | HRESULT result = (*d3dintf->device.end_scene)(m_device); |
| 796 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device end_scene call\n", (int)result); |
| 797 | |
| 798 | // present the current buffers |
| 799 | result = (*d3dintf->device.present)(m_device, NULL, NULL, NULL, NULL, 0); |
| 800 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device present call\n", (int)result); |
| 801 | } |
| 802 | |
| 803 | //============================================================ |
| 804 | // device_create |
| 805 | //============================================================ |
| 806 | |
| 807 | int renderer::device_create(HWND device_hwnd) |
| 808 | { |
| 809 | // if a device exists, free it |
| 810 | if (m_device != NULL) |
| 811 | { |
| 812 | device_delete(); |
| 813 | } |
| 814 | |
| 815 | // create shader options only once |
| 816 | if (m_shaders_options == NULL) |
| 817 | { |
| 818 | m_shaders_options = (hlsl_options*)global_alloc_clear(hlsl_options); |
| 819 | } |
| 820 | |
| 821 | // verify the caps |
| 822 | int verify = device_verify_caps(); |
| 823 | if (verify == 2) |
| 824 | { |
| 825 | osd_printf_error("Error: Device does not meet minimum requirements for Direct3D rendering\n"); |
| 826 | return 1; |
| 827 | } |
| 828 | if (verify == 1) |
| 829 | { |
| 830 | osd_printf_warning("Warning: Device may not perform well for Direct3D rendering\n"); |
| 831 | } |
| 832 | |
| 833 | // verify texture formats |
| 834 | HRESULT result = (*d3dintf->d3d.check_device_format)(d3dintf, m_adapter, D3DDEVTYPE_HAL, m_pixformat, 0, D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8); |
| 835 | if (result != D3D_OK) |
| 836 | { |
| 837 | osd_printf_error("Error: A8R8G8B8 format textures not supported\n"); |
| 838 | return 1; |
| 839 | } |
| 840 | |
| 841 | m_texture_manager = global_alloc(texture_manager(this)); |
| 842 | |
| 843 | try_again: |
| 844 | // try for XRGB first |
| 845 | m_screen_format = D3DFMT_X8R8G8B8; |
| 846 | result = (*d3dintf->d3d.check_device_format)(d3dintf, m_adapter, D3DDEVTYPE_HAL, m_pixformat, m_texture_manager->is_dynamic_supported() ? D3DUSAGE_DYNAMIC : 0, D3DRTYPE_TEXTURE, m_screen_format); |
| 847 | if (result != D3D_OK) |
| 848 | { |
| 849 | // if not, try for ARGB |
| 850 | m_screen_format = D3DFMT_A8R8G8B8; |
| 851 | result = (*d3dintf->d3d.check_device_format)(d3dintf, m_adapter, D3DDEVTYPE_HAL, m_pixformat, m_texture_manager->is_dynamic_supported() ? D3DUSAGE_DYNAMIC : 0, D3DRTYPE_TEXTURE, m_screen_format); |
| 852 | if (result != D3D_OK && m_texture_manager->is_dynamic_supported()) |
| 853 | { |
| 854 | m_texture_manager->set_dynamic_supported(FALSE); |
| 855 | goto try_again; |
| 856 | } |
| 857 | if (result != D3D_OK) |
| 858 | { |
| 859 | osd_printf_error("Error: unable to configure a screen texture format\n"); |
| 860 | return 1; |
| 861 | } |
| 862 | } |
| 863 | |
| 864 | // initialize the D3D presentation parameters |
| 865 | memset(&m_presentation, 0, sizeof(m_presentation)); |
| 866 | m_presentation.BackBufferWidth = m_width; |
| 867 | m_presentation.BackBufferHeight = m_height; |
| 868 | m_presentation.BackBufferFormat = m_pixformat; |
| 869 | m_presentation.BackBufferCount = video_config.triplebuf ? 2 : 1; |
| 870 | m_presentation.MultiSampleType = D3DMULTISAMPLE_NONE; |
| 871 | m_presentation.SwapEffect = D3DSWAPEFFECT_DISCARD; |
| 872 | m_presentation.hDeviceWindow = window().m_hwnd; |
| 873 | m_presentation.Windowed = !window().fullscreen() || window().win_has_menu(); |
| 874 | m_presentation.EnableAutoDepthStencil = FALSE; |
| 875 | m_presentation.AutoDepthStencilFormat = D3DFMT_D16; |
| 876 | m_presentation.Flags = 0; |
| 877 | m_presentation.FullScreen_RefreshRateInHz = m_refresh; |
| 878 | m_presentation.PresentationInterval = ((video_config.triplebuf && window().fullscreen()) || |
| 879 | video_config.waitvsync || video_config.syncrefresh) ? |
| 880 | D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE; |
| 881 | |
| 882 | // create the D3D device |
| 883 | result = (*d3dintf->d3d.create_device)(d3dintf, m_adapter, D3DDEVTYPE_HAL, device_hwnd, |
| 884 | D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &m_presentation, &m_device); |
| 885 | if (result != D3D_OK) |
| 886 | { |
| 887 | // if we got a "DEVICELOST" error, it may be transitory; count it and only fail if |
| 888 | // we exceed a threshold |
| 889 | if (result == D3DERR_DEVICELOST) |
| 890 | { |
| 891 | m_create_error_count++; |
| 892 | if (m_create_error_count < 10) |
| 893 | { |
| 894 | return 0; |
| 895 | } |
| 896 | } |
| 897 | |
| 898 | // fatal error if we just can't do it |
| 899 | osd_printf_error("Unable to create the Direct3D device (%08X)\n", (UINT32)result); |
| 900 | return 1; |
| 901 | } |
| 902 | m_create_error_count = 0; |
| 903 | osd_printf_verbose("Direct3D: Device created at %dx%d\n", m_width, m_height); |
| 904 | |
| 905 | // set the gamma if we need to |
| 906 | if (window().fullscreen()) |
| 907 | { |
| 908 | // only set the gamma if it's not 1.0f |
| 909 | windows_options &options = downcast<windows_options &>(window().machine().options()); |
| 910 | float brightness = options.full_screen_brightness(); |
| 911 | float contrast = options.full_screen_contrast(); |
| 912 | float gamma = options.full_screen_gamma(); |
| 913 | if (brightness != 1.0f || contrast != 1.0f || gamma != 1.0f) |
| 914 | { |
| 915 | // warn if we can't do it |
| 916 | if (!m_gamma_supported) |
| 917 | { |
| 918 | osd_printf_warning("Direct3D: Warning - device does not support full screen gamma correction.\n"); |
| 919 | } |
| 920 | else |
| 921 | { |
| 922 | // create a standard ramp and set it |
| 923 | D3DGAMMARAMP ramp; |
| 924 | for (int i = 0; i < 256; i++) |
| 925 | { |
| 926 | ramp.red[i] = ramp.green[i] = ramp.blue[i] = apply_brightness_contrast_gamma(i, brightness, contrast, gamma) << 8; |
| 927 | } |
| 928 | (*d3dintf->device.set_gamma_ramp)(m_device, 0, &ramp); |
| 929 | } |
| 930 | } |
| 931 | } |
| 932 | |
| 933 | int ret = m_shaders->create_resources(false); |
| 934 | if (ret != 0) |
| 935 | return ret; |
| 936 | |
| 937 | return device_create_resources(); |
| 938 | } |
| 939 | |
| 940 | |
| 941 | //============================================================ |
| 942 | // device_create_resources |
| 943 | //============================================================ |
| 944 | |
| 945 | int renderer::device_create_resources() |
| 946 | { |
| 947 | // allocate a vertex buffer to use |
| 948 | HRESULT result = (*d3dintf->device.create_vertex_buffer)(m_device, |
| 949 | sizeof(vertex) * VERTEX_BUFFER_SIZE, |
| 950 | D3DUSAGE_DYNAMIC | D3DUSAGE_SOFTWAREPROCESSING | D3DUSAGE_WRITEONLY, |
| 951 | VERTEX_BASE_FORMAT | ((m_shaders->enabled() && d3dintf->post_fx_available) ? D3DFVF_XYZW : D3DFVF_XYZRHW), |
| 952 | D3DPOOL_DEFAULT, &m_vertexbuf); |
| 953 | if (result != D3D_OK) |
| 954 | { |
| 955 | osd_printf_error("Error creating vertex buffer (%08X)\n", (UINT32)result); |
| 956 | return 1; |
| 957 | } |
| 958 | |
| 959 | // set the vertex format |
| 960 | result = (*d3dintf->device.set_vertex_format)(m_device, (D3DFORMAT)(VERTEX_BASE_FORMAT | ((m_shaders->enabled() && |
| 961 | d3dintf->post_fx_available) ? D3DFVF_XYZW : D3DFVF_XYZRHW))); |
| 962 | if (result != D3D_OK) |
| 963 | { |
| 964 | osd_printf_error("Error setting vertex format (%08X)\n", (UINT32)result); |
| 965 | return 1; |
| 966 | } |
| 967 | |
| 968 | // set the fixed render state |
| 969 | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ZENABLE, D3DZB_FALSE); |
| 970 | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_FILLMODE, D3DFILL_SOLID); |
| 971 | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_SHADEMODE, D3DSHADE_FLAT); |
| 972 | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ZWRITEENABLE, FALSE); |
| 973 | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ALPHATESTENABLE, TRUE); |
| 974 | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_LASTPIXEL, TRUE); |
| 975 | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_CULLMODE, D3DCULL_NONE); |
| 976 | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ZFUNC, D3DCMP_LESS); |
| 977 | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ALPHAREF, 0); |
| 978 | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_ALPHAFUNC, D3DCMP_GREATER); |
| 979 | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_DITHERENABLE, FALSE); |
| 980 | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_FOGENABLE, FALSE); |
| 981 | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_SPECULARENABLE, FALSE); |
| 982 | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_STENCILENABLE, FALSE); |
| 983 | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_WRAP0, FALSE); |
| 984 | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_CLIPPING, TRUE); |
| 985 | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_LIGHTING, FALSE); |
| 986 | result = (*d3dintf->device.set_render_state)(m_device, D3DRS_COLORVERTEX, TRUE); |
| 987 | |
| 988 | result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, D3DTSS_COLOROP, D3DTOP_MODULATE); |
| 989 | result = (*d3dintf->device.set_texture_stage_state)(m_device, 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); |
| 990 | result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, D3DTSS_COLOROP, D3DTOP_MODULATE); |
| 991 | result = (*d3dintf->device.set_texture_stage_state)(m_device, 1, D3DTSS_ALPHAOP, D3DTOP_MODULATE); |
| 992 | |
| 993 | // reset the local states to force updates |
| 994 | reset_render_states(); |
| 995 | |
| 996 | // clear the buffer |
| 997 | result = (*d3dintf->device.clear)(m_device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); |
| 998 | result = (*d3dintf->device.present)(m_device, NULL, NULL, NULL, NULL, 0); |
| 999 | |
| 1000 | m_texture_manager->create_resources(); |
| 1001 | |
| 1002 | return 0; |
| 1003 | } |
| 1004 | |
| 1005 | |
| 1006 | //============================================================ |
| 1007 | // device_delete |
| 1008 | //============================================================ |
| 1009 | |
| 1010 | renderer::~renderer() |
| 1011 | { |
| 1012 | if (m_shaders_options != NULL) |
| 1013 | { |
| 1014 | global_free(m_shaders_options); |
| 1015 | } |
| 1016 | m_shaders_options = NULL; |
| 1017 | |
| 1018 | device_delete(); |
| 1019 | } |
| 1020 | |
| 1021 | void renderer::device_delete() |
| 1022 | { |
| 1023 | if (m_shaders != NULL) |
| 1024 | { |
| 1025 | // free our effects |
| 1026 | m_shaders->delete_resources(false); |
| 1027 | |
| 1028 | // delete the HLSL interface |
| 1029 | global_free(m_shaders); |
| 1030 | } |
| 1031 | |
| 1032 | // free our base resources |
| 1033 | device_delete_resources(); |
| 1034 | |
| 1035 | if (m_texture_manager != NULL) |
| 1036 | { |
| 1037 | global_free(m_texture_manager); |
| 1038 | } |
| 1039 | m_texture_manager = NULL; |
| 1040 | |
| 1041 | // free the device itself |
| 1042 | if (m_device != NULL) |
| 1043 | { |
| 1044 | (*d3dintf->device.reset)(m_device, &m_presentation); |
| 1045 | (*d3dintf->device.release)(m_device); |
| 1046 | } |
| 1047 | m_device = NULL; |
| 1048 | } |
| 1049 | |
| 1050 | |
| 1051 | //============================================================ |
| 1052 | // device_delete_resources |
| 1053 | //============================================================ |
| 1054 | |
| 1055 | void renderer::device_delete_resources() |
| 1056 | { |
| 1057 | if (m_texture_manager != NULL) |
| 1058 | m_texture_manager->delete_resources(); |
| 1059 | // free the vertex buffer |
| 1060 | if (m_vertexbuf != NULL) |
| 1061 | (*d3dintf->vertexbuf.release)(m_vertexbuf); |
| 1062 | m_vertexbuf = NULL; |
| 1063 | } |
| 1064 | |
| 1065 | |
| 1066 | //============================================================ |
| 1067 | // device_verify_caps |
| 1068 | //============================================================ |
| 1069 | |
| 1070 | int renderer::device_verify_caps() |
| 1071 | { |
| 1072 | int retval = 0; |
| 1073 | |
| 1074 | m_shaders = (shaders*)global_alloc_clear(shaders); |
| 1075 | m_shaders->init(d3dintf, &window().machine(), this); |
| 1076 | |
| 1077 | DWORD tempcaps; |
| 1078 | HRESULT result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_MAX_PS30_INSN_SLOTS, &tempcaps); |
| 1079 | if (result != D3D_OK) osd_printf_verbose("Direct3D Error %08X during get_caps_dword call\n", (int)result); |
| 1080 | if (tempcaps < 512) |
| 1081 | { |
| 1082 | osd_printf_verbose("Direct3D: Warning - Device does not support Pixel Shader 3.0, falling back to non-PS rendering\n"); |
| 1083 | d3dintf->post_fx_available = false; |
| 1084 | } |
| 1085 | |
| 1086 | // verify presentation capabilities |
| 1087 | result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_PRESENTATION_INTERVALS, &tempcaps); |
| 1088 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result); |
| 1089 | if (!(tempcaps & D3DPRESENT_INTERVAL_IMMEDIATE)) |
| 1090 | { |
| 1091 | osd_printf_verbose("Direct3D: Error - Device does not support immediate presentations\n"); |
| 1092 | retval = 2; |
| 1093 | } |
| 1094 | if (!(tempcaps & D3DPRESENT_INTERVAL_ONE)) |
| 1095 | { |
| 1096 | osd_printf_verbose("Direct3D: Error - Device does not support per-refresh presentations\n"); |
| 1097 | retval = 2; |
| 1098 | } |
| 1099 | |
| 1100 | // verify device capabilities |
| 1101 | result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_DEV_CAPS, &tempcaps); |
| 1102 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result); |
| 1103 | if (!(tempcaps & D3DDEVCAPS_CANRENDERAFTERFLIP)) |
| 1104 | { |
| 1105 | osd_printf_verbose("Direct3D: Warning - Device does not support queued rendering after a page flip\n"); |
| 1106 | retval = 1; |
| 1107 | } |
| 1108 | if (!(tempcaps & D3DDEVCAPS_HWRASTERIZATION)) |
| 1109 | { |
| 1110 | osd_printf_verbose("Direct3D: Warning - Device does not support hardware rasterization\n"); |
| 1111 | retval = 1; |
| 1112 | } |
| 1113 | |
| 1114 | // verify texture operation capabilities |
| 1115 | result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_TEXTURE_OP_CAPS, &tempcaps); |
| 1116 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result); |
| 1117 | if (!(tempcaps & D3DTEXOPCAPS_MODULATE)) |
| 1118 | { |
| 1119 | osd_printf_verbose("Direct3D: Warning - Device does not support texture modulation\n"); |
| 1120 | retval = 1; |
| 1121 | } |
| 1122 | |
| 1123 | // set a simpler flag to indicate mod2x and mod4x texture modes |
| 1124 | m_mod2x_supported = ((tempcaps & D3DTEXOPCAPS_MODULATE2X) != 0); |
| 1125 | m_mod4x_supported = ((tempcaps & D3DTEXOPCAPS_MODULATE4X) != 0); |
| 1126 | |
| 1127 | result = (*d3dintf->d3d.get_caps_dword)(d3dintf, m_adapter, D3DDEVTYPE_HAL, CAPS_CAPS2, &tempcaps); |
| 1128 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during get_caps_dword call\n", (int)result); |
| 1129 | m_gamma_supported = ((tempcaps & D3DCAPS2_FULLSCREENGAMMA) != 0); |
| 1130 | |
| 1131 | return retval; |
| 1132 | } |
| 1133 | |
| 1134 | |
| 1135 | //============================================================ |
| 1136 | // device_test_cooperative |
| 1137 | //============================================================ |
| 1138 | |
| 1139 | int renderer::device_test_cooperative() |
| 1140 | { |
| 1141 | // check our current status; if we lost the device, punt to GDI |
| 1142 | HRESULT result = (*d3dintf->device.test_cooperative_level)(m_device); |
| 1143 | if (result == D3DERR_DEVICELOST) |
| 1144 | return 1; |
| 1145 | |
| 1146 | // if we're able to reset ourselves, try it |
| 1147 | if (result == D3DERR_DEVICENOTRESET) |
| 1148 | { |
| 1149 | osd_printf_verbose("Direct3D: resetting device\n"); |
| 1150 | |
| 1151 | // free all existing resources and call reset on the device |
| 1152 | //device_delete(); |
| 1153 | device_delete_resources(); |
| 1154 | m_shaders->delete_resources(true); |
| 1155 | result = (*d3dintf->device.reset)(m_device, &m_presentation); |
| 1156 | |
| 1157 | // if it didn't work, punt to GDI |
| 1158 | if (result != D3D_OK) |
| 1159 | { |
| 1160 | osd_printf_error("Unable to reset, result %08x\n", (UINT32)result); |
| 1161 | return 1; |
| 1162 | } |
| 1163 | |
| 1164 | // try to create the resources again; if that didn't work, delete the whole thing |
| 1165 | if (device_create_resources()) |
| 1166 | { |
| 1167 | osd_printf_verbose("Direct3D: failed to recreate resources for device; failing permanently\n"); |
| 1168 | device_delete(); |
| 1169 | return 1; |
| 1170 | } |
| 1171 | |
| 1172 | if (m_shaders->create_resources(true)) |
| 1173 | { |
| 1174 | osd_printf_verbose("Direct3D: failed to recreate HLSL resources for device; failing permanently\n"); |
| 1175 | device_delete(); |
| 1176 | return 1; |
| 1177 | } |
| 1178 | } |
| 1179 | return 0; |
| 1180 | } |
| 1181 | |
| 1182 | |
| 1183 | //============================================================ |
| 1184 | // config_adapter_mode |
| 1185 | //============================================================ |
| 1186 | |
| 1187 | int renderer::config_adapter_mode() |
| 1188 | { |
| 1189 | adapter_identifier identifier; |
| 1190 | |
| 1191 | // choose the monitor number |
| 1192 | m_adapter = get_adapter_for_monitor(); |
| 1193 | |
| 1194 | // get the identifier |
| 1195 | HRESULT result = (*d3dintf->d3d.get_adapter_identifier)(d3dintf, m_adapter, 0, &identifier); |
| 1196 | if (result != D3D_OK) |
| 1197 | { |
| 1198 | osd_printf_error("Error getting identifier for adapter #%d\n", m_adapter); |
| 1199 | return 1; |
| 1200 | } |
| 1201 | osd_printf_verbose("Direct3D: Configuring adapter #%d = %s\n", m_adapter, identifier.Description); |
| 1202 | |
| 1203 | // get the current display mode |
| 1204 | result = (*d3dintf->d3d.get_adapter_display_mode)(d3dintf, m_adapter, &m_origmode); |
| 1205 | if (result != D3D_OK) |
| 1206 | { |
| 1207 | osd_printf_error("Error getting mode for adapter #%d\n", m_adapter); |
| 1208 | return 1; |
| 1209 | } |
| 1210 | |
| 1211 | // choose a resolution: window mode case |
| 1212 | if (!window().fullscreen() || !video_config.switchres || window().win_has_menu()) |
| 1213 | { |
| 1214 | RECT client; |
| 1215 | |
| 1216 | // bounds are from the window client rect |
| 1217 | GetClientRectExceptMenu(window().m_hwnd, &client, window().fullscreen()); |
| 1218 | m_width = client.right - client.left; |
| 1219 | m_height = client.bottom - client.top; |
| 1220 | |
| 1221 | // pix format is from the current mode |
| 1222 | m_pixformat = m_origmode.Format; |
| 1223 | m_refresh = 0; |
| 1224 | |
| 1225 | // make sure it's a pixel format we can get behind |
| 1226 | if (m_pixformat != D3DFMT_X1R5G5B5 && m_pixformat != D3DFMT_R5G6B5 && m_pixformat != D3DFMT_X8R8G8B8) |
| 1227 | { |
| 1228 | osd_printf_error("Device %s currently in an unsupported mode\n", window().monitor()->devicename()); |
| 1229 | return 1; |
| 1230 | } |
| 1231 | } |
| 1232 | |
| 1233 | // choose a resolution: full screen mode case |
| 1234 | else |
| 1235 | { |
| 1236 | // default to the current mode exactly |
| 1237 | m_width = m_origmode.Width; |
| 1238 | m_height = m_origmode.Height; |
| 1239 | m_pixformat = m_origmode.Format; |
| 1240 | m_refresh = m_origmode.RefreshRate; |
| 1241 | |
| 1242 | // if we're allowed to switch resolutions, override with something better |
| 1243 | if (video_config.switchres) |
| 1244 | pick_best_mode(); |
| 1245 | } |
| 1246 | |
| 1247 | // see if we can handle the device type |
| 1248 | result = (*d3dintf->d3d.check_device_type)(d3dintf, m_adapter, D3DDEVTYPE_HAL, m_pixformat, m_pixformat, !window().fullscreen()); |
| 1249 | if (result != D3D_OK) |
| 1250 | { |
| 1251 | osd_printf_error("Proposed video mode not supported on device %s\n", window().monitor()->devicename()); |
| 1252 | return 1; |
| 1253 | } |
| 1254 | return 0; |
| 1255 | } |
| 1256 | |
| 1257 | |
| 1258 | //============================================================ |
| 1259 | // get_adapter_for_monitor |
| 1260 | //============================================================ |
| 1261 | |
| 1262 | int renderer::get_adapter_for_monitor() |
| 1263 | { |
| 1264 | int maxadapter = (*d3dintf->d3d.get_adapter_count)(d3dintf); |
| 1265 | |
| 1266 | // iterate over adapters until we error or find a match |
| 1267 | for (int adapternum = 0; adapternum < maxadapter; adapternum++) |
| 1268 | { |
| 1269 | // get the monitor for this adapter |
| 1270 | HMONITOR curmonitor = (*d3dintf->d3d.get_adapter_monitor)(d3dintf, adapternum); |
| 1271 | |
| 1272 | // if we match the proposed monitor, this is it |
| 1273 | if (curmonitor == *((HMONITOR *)window().monitor()->oshandle())) |
| 1274 | { |
| 1275 | return adapternum; |
| 1276 | } |
| 1277 | } |
| 1278 | |
| 1279 | // default to the default |
| 1280 | return D3DADAPTER_DEFAULT; |
| 1281 | } |
| 1282 | |
| 1283 | |
| 1284 | //============================================================ |
| 1285 | // pick_best_mode |
| 1286 | //============================================================ |
| 1287 | |
| 1288 | void renderer::pick_best_mode() |
| 1289 | { |
| 1290 | double target_refresh = 60.0; |
| 1291 | INT32 minwidth, minheight; |
| 1292 | float best_score = 0.0f; |
| 1293 | |
| 1294 | // determine the refresh rate of the primary screen |
| 1295 | const screen_device *primary_screen = window().machine().config().first_screen(); |
| 1296 | if (primary_screen != NULL) |
| 1297 | { |
| 1298 | target_refresh = ATTOSECONDS_TO_HZ(primary_screen->refresh_attoseconds()); |
| 1299 | } |
| 1300 | |
| 1301 | // determine the minimum width/height for the selected target |
| 1302 | // note: technically we should not be calling this from an alternate window |
| 1303 | // thread; however, it is only done during init time, and the init code on |
| 1304 | // the main thread is waiting for us to finish, so it is safe to do so here |
| 1305 | window().target()->compute_minimum_size(minwidth, minheight); |
| 1306 | |
| 1307 | // use those as the target for now |
| 1308 | INT32 target_width = minwidth; |
| 1309 | INT32 target_height = minheight; |
| 1310 | |
| 1311 | // determine the maximum number of modes |
| 1312 | int maxmodes = (*d3dintf->d3d.get_adapter_mode_count)(d3dintf, m_adapter, D3DFMT_X8R8G8B8); |
| 1313 | |
| 1314 | // enumerate all the video modes and find the best match |
| 1315 | osd_printf_verbose("Direct3D: Selecting video mode...\n"); |
| 1316 | for (int modenum = 0; modenum < maxmodes; modenum++) |
| 1317 | { |
| 1318 | // check this mode |
| 1319 | D3DDISPLAYMODE mode; |
| 1320 | HRESULT result = (*d3dintf->d3d.enum_adapter_modes)(d3dintf, m_adapter, D3DFMT_X8R8G8B8, modenum, &mode); |
| 1321 | if (result != D3D_OK) |
| 1322 | break; |
| 1323 | |
| 1324 | // skip non-32 bit modes |
| 1325 | if (mode.Format != D3DFMT_X8R8G8B8) |
| 1326 | continue; |
| 1327 | |
| 1328 | // compute initial score based on difference between target and current |
| 1329 | float size_score = 1.0f / (1.0f + fabs((float)(mode.Width - target_width)) + fabs((float)(mode.Height - target_height))); |
| 1330 | |
| 1331 | // if the mode is too small, give a big penalty |
| 1332 | if (mode.Width < minwidth || mode.Height < minheight) |
| 1333 | size_score *= 0.01f; |
| 1334 | |
| 1335 | // if mode is smaller than we'd like, it only scores up to 0.1 |
| 1336 | if (mode.Width < target_width || mode.Height < target_height) |
| 1337 | size_score *= 0.1f; |
| 1338 | |
| 1339 | // if we're looking for a particular mode, that's a winner |
| 1340 | if (mode.Width == window().m_win_config.width && mode.Height == window().m_win_config.height) |
| 1341 | size_score = 2.0f; |
| 1342 | |
| 1343 | // compute refresh score |
| 1344 | float refresh_score = 1.0f / (1.0f + fabs((double)mode.RefreshRate - target_refresh)); |
| 1345 | |
| 1346 | // if refresh is smaller than we'd like, it only scores up to 0.1 |
| 1347 | if ((double)mode.RefreshRate < target_refresh) |
| 1348 | refresh_score *= 0.1f; |
| 1349 | |
| 1350 | // if we're looking for a particular refresh, make sure it matches |
| 1351 | if (mode.RefreshRate == window().m_win_config.refresh) |
| 1352 | refresh_score = 2.0f; |
| 1353 | |
| 1354 | // weight size and refresh equally |
| 1355 | float final_score = size_score + refresh_score; |
| 1356 | |
| 1357 | // best so far? |
| 1358 | osd_printf_verbose(" %4dx%4d@%3dHz -> %f\n", mode.Width, mode.Height, mode.RefreshRate, final_score * 1000.0f); |
| 1359 | if (final_score > best_score) |
| 1360 | { |
| 1361 | best_score = final_score; |
| 1362 | m_width = mode.Width; |
| 1363 | m_height = mode.Height; |
| 1364 | m_pixformat = mode.Format; |
| 1365 | m_refresh = mode.RefreshRate; |
| 1366 | } |
| 1367 | } |
| 1368 | osd_printf_verbose("Direct3D: Mode selected = %4dx%4d@%3dHz\n", m_width, m_height, m_refresh); |
| 1369 | } |
| 1370 | |
| 1371 | |
| 1372 | //============================================================ |
| 1373 | // update_window_size |
| 1374 | //============================================================ |
| 1375 | |
| 1376 | int renderer::update_window_size() |
| 1377 | { |
| 1378 | // get the current window bounds |
| 1379 | RECT client; |
| 1380 | GetClientRectExceptMenu(window().m_hwnd, &client, window().fullscreen()); |
| 1381 | |
| 1382 | // if we have a device and matching width/height, nothing to do |
| 1383 | if (m_device != NULL && rect_width(&client) == m_width && rect_height(&client) == m_height) |
| 1384 | { |
| 1385 | // clear out any pending resizing if the area didn't change |
| 1386 | if (window().m_resize_state == RESIZE_STATE_PENDING) |
| 1387 | window().m_resize_state = RESIZE_STATE_NORMAL; |
| 1388 | return FALSE; |
| 1389 | } |
| 1390 | |
| 1391 | // if we're in the middle of resizing, leave it alone as well |
| 1392 | if (window().m_resize_state == RESIZE_STATE_RESIZING) |
| 1393 | return FALSE; |
| 1394 | |
| 1395 | // set the new bounds and create the device again |
| 1396 | m_width = rect_width(&client); |
| 1397 | m_height = rect_height(&client); |
| 1398 | if (device_create(window().m_focus_hwnd)) |
| 1399 | return FALSE; |
| 1400 | |
| 1401 | // reset the resize state to normal, and indicate we made a change |
| 1402 | window().m_resize_state = RESIZE_STATE_NORMAL; |
| 1403 | return TRUE; |
| 1404 | } |
| 1405 | |
| 1406 | |
| 1407 | //============================================================ |
| 1408 | // batch_vectors |
| 1409 | //============================================================ |
| 1410 | |
| 1411 | void renderer::batch_vectors() |
| 1412 | { |
| 1413 | windows_options &options = downcast<windows_options &>(window().machine().options()); |
| 1414 | |
| 1415 | int vector_size = (options.antialias() ? 24 : 6); |
| 1416 | m_vectorbatch = mesh_alloc(m_line_count * vector_size); |
| 1417 | m_batchindex = 0; |
| 1418 | |
| 1419 | static int start_index = 0; |
| 1420 | int line_index = 0; |
| 1421 | float period = options.screen_vector_time_period(); |
| 1422 | UINT32 cached_flags = 0; |
| 1423 | for (render_primitive *prim = window().m_primlist->first(); prim != NULL; prim = prim->next()) |
| 1424 | { |
| 1425 | switch (prim->type) |
| 1426 | { |
| 1427 | case render_primitive::LINE: |
| 1428 | if (PRIMFLAG_GET_VECTOR(prim->flags)) |
| 1429 | { |
| 1430 | if (period == 0.0f || m_line_count == 0) |
| 1431 | { |
| 1432 | batch_vector(prim, 1.0f); |
| 1433 | } |
| 1434 | else |
| 1435 | { |
| 1436 | batch_vector(prim, (float)(start_index + line_index) / ((float)m_line_count * period)); |
| 1437 | line_index++; |
| 1438 | } |
| 1439 | cached_flags = prim->flags; |
| 1440 | } |
| 1441 | break; |
| 1442 | |
| 1443 | default: |
| 1444 | // Skip |
| 1445 | break; |
| 1446 | } |
| 1447 | } |
| 1448 | |
| 1449 | // now add a polygon entry |
| 1450 | m_poly[m_numpolys].init(D3DPT_TRIANGLELIST, m_line_count * (options.antialias() ? 8 : 2), vector_size * m_line_count, cached_flags, |
| 1451 | m_texture_manager->get_vector_texture(), D3DTOP_MODULATE, 0.0f, 1.0f, 0.0f, 0.0f); |
| 1452 | m_numpolys++; |
| 1453 | |
| 1454 | start_index += (int)((float)line_index * period); |
| 1455 | if (m_line_count > 0) |
| 1456 | { |
| 1457 | start_index %= m_line_count; |
| 1458 | } |
| 1459 | |
| 1460 | m_line_count = 0; |
| 1461 | } |
| 1462 | |
| 1463 | void renderer::batch_vector(const render_primitive *prim, float line_time) |
| 1464 | { |
| 1465 | // compute the effective width based on the direction of the line |
| 1466 | float effwidth = prim->width; |
| 1467 | if (effwidth < 0.5f) |
| 1468 | { |
| 1469 | effwidth = 0.5f; |
| 1470 | } |
| 1471 | |
| 1472 | // determine the bounds of a quad to draw this line |
| 1473 | render_bounds b0, b1; |
| 1474 | render_line_to_quad(&prim->bounds, effwidth, &b0, &b1); |
| 1475 | |
| 1476 | // iterate over AA steps |
| 1477 | for (const line_aa_step *step = PRIMFLAG_GET_ANTIALIAS(prim->flags) ? line_aa_4step : line_aa_1step; |
| 1478 | step->weight != 0; step++) |
| 1479 | { |
| 1480 | // get a pointer to the vertex buffer |
| 1481 | if (m_vectorbatch == NULL) |
| 1482 | return; |
| 1483 | |
| 1484 | m_vectorbatch[m_batchindex + 0].x = b0.x0 + step->xoffs; |
| 1485 | m_vectorbatch[m_batchindex + 0].y = b0.y0 + step->yoffs; |
| 1486 | m_vectorbatch[m_batchindex + 1].x = b0.x1 + step->xoffs; |
| 1487 | m_vectorbatch[m_batchindex + 1].y = b0.y1 + step->yoffs; |
| 1488 | m_vectorbatch[m_batchindex + 2].x = b1.x0 + step->xoffs; |
| 1489 | m_vectorbatch[m_batchindex + 2].y = b1.y0 + step->yoffs; |
| 1490 | |
| 1491 | m_vectorbatch[m_batchindex + 3].x = b0.x1 + step->xoffs; |
| 1492 | m_vectorbatch[m_batchindex + 3].y = b0.y1 + step->yoffs; |
| 1493 | m_vectorbatch[m_batchindex + 4].x = b1.x0 + step->xoffs; |
| 1494 | m_vectorbatch[m_batchindex + 4].y = b1.y0 + step->yoffs; |
| 1495 | m_vectorbatch[m_batchindex + 5].x = b1.x1 + step->xoffs; |
| 1496 | m_vectorbatch[m_batchindex + 5].y = b1.y1 + step->yoffs; |
| 1497 | |
| 1498 | float dx = b1.x1 - b0.x1; |
| 1499 | float dy = b1.y1 - b0.y1; |
| 1500 | float line_length = sqrtf(dx * dx + dy * dy); |
| 1501 | |
| 1502 | // determine the color of the line |
| 1503 | INT32 r = (INT32)(prim->color.r * step->weight * 255.0f); |
| 1504 | INT32 g = (INT32)(prim->color.g * step->weight * 255.0f); |
| 1505 | INT32 b = (INT32)(prim->color.b * step->weight * 255.0f); |
| 1506 | INT32 a = (INT32)(prim->color.a * 255.0f); |
| 1507 | if (r > 255 || g > 255 || b > 255) |
| 1508 | { |
| 1509 | if (r > 2*255 || g > 2*255 || b > 2*255) |
| 1510 | { |
| 1511 | r >>= 2; g >>= 2; b >>= 2; |
| 1512 | } |
| 1513 | else |
| 1514 | { |
| 1515 | r >>= 1; g >>= 1; b >>= 1; |
| 1516 | } |
| 1517 | } |
| 1518 | if (r > 255) r = 255; |
| 1519 | if (g > 255) g = 255; |
| 1520 | if (b > 255) b = 255; |
| 1521 | if (a > 255) a = 255; |
| 1522 | DWORD color = D3DCOLOR_ARGB(a, r, g, b); |
| 1523 | |
| 1524 | vec2f& start = (get_vector_texture() ? get_vector_texture()->get_uvstart() : get_default_texture()->get_uvstart()); |
| 1525 | vec2f& stop = (get_vector_texture() ? get_vector_texture()->get_uvstop() : get_default_texture()->get_uvstop()); |
| 1526 | |
| 1527 | m_vectorbatch[m_batchindex + 0].u0 = start.c.x; |
| 1528 | m_vectorbatch[m_batchindex + 0].v0 = start.c.y; |
| 1529 | m_vectorbatch[m_batchindex + 1].u0 = start.c.x; |
| 1530 | m_vectorbatch[m_batchindex + 1].v0 = stop.c.y; |
| 1531 | m_vectorbatch[m_batchindex + 2].u0 = stop.c.x; |
| 1532 | m_vectorbatch[m_batchindex + 2].v0 = start.c.y; |
| 1533 | |
| 1534 | m_vectorbatch[m_batchindex + 3].u0 = start.c.x; |
| 1535 | m_vectorbatch[m_batchindex + 3].v0 = stop.c.y; |
| 1536 | m_vectorbatch[m_batchindex + 4].u0 = stop.c.x; |
| 1537 | m_vectorbatch[m_batchindex + 4].v0 = start.c.y; |
| 1538 | m_vectorbatch[m_batchindex + 5].u0 = stop.c.x; |
| 1539 | m_vectorbatch[m_batchindex + 5].v0 = stop.c.y; |
| 1540 | |
| 1541 | m_vectorbatch[m_batchindex + 0].u1 = line_length; |
| 1542 | m_vectorbatch[m_batchindex + 1].u1 = line_length; |
| 1543 | m_vectorbatch[m_batchindex + 2].u1 = line_length; |
| 1544 | m_vectorbatch[m_batchindex + 3].u1 = line_length; |
| 1545 | m_vectorbatch[m_batchindex + 4].u1 = line_length; |
| 1546 | m_vectorbatch[m_batchindex + 5].u1 = line_length; |
| 1547 | |
| 1548 | // set the color, Z parameters to standard values |
| 1549 | for (int i = 0; i < 6; i++) |
| 1550 | { |
| 1551 | m_vectorbatch[m_batchindex + i].z = 0.0f; |
| 1552 | m_vectorbatch[m_batchindex + i].rhw = 1.0f; |
| 1553 | m_vectorbatch[m_batchindex + i].color = color; |
| 1554 | } |
| 1555 | |
| 1556 | m_batchindex += 6; |
| 1557 | } |
| 1558 | } |
| 1559 | |
| 1560 | |
| 1561 | //============================================================ |
| 1562 | // draw_line |
| 1563 | //============================================================ |
| 1564 | |
| 1565 | void renderer::draw_line(const render_primitive *prim) |
| 1566 | { |
| 1567 | // compute the effective width based on the direction of the line |
| 1568 | float effwidth = prim->width; |
| 1569 | if (effwidth < 0.5f) |
| 1570 | { |
| 1571 | effwidth = 0.5f; |
| 1572 | } |
| 1573 | |
| 1574 | // determine the bounds of a quad to draw this line |
| 1575 | render_bounds b0, b1; |
| 1576 | render_line_to_quad(&prim->bounds, effwidth, &b0, &b1); |
| 1577 | |
| 1578 | // iterate over AA steps |
| 1579 | for (const line_aa_step *step = PRIMFLAG_GET_ANTIALIAS(prim->flags) ? line_aa_4step : line_aa_1step; |
| 1580 | step->weight != 0; step++) |
| 1581 | { |
| 1582 | // get a pointer to the vertex buffer |
| 1583 | vertex *vertex = mesh_alloc(4); |
| 1584 | if (vertex == NULL) |
| 1585 | return; |
| 1586 | |
| 1587 | // rotate the unit vector by 135 degrees and add to point 0 |
| 1588 | vertex[0].x = b0.x0 + step->xoffs; |
| 1589 | vertex[0].y = b0.y0 + step->yoffs; |
| 1590 | |
| 1591 | // rotate the unit vector by -135 degrees and add to point 0 |
| 1592 | vertex[1].x = b0.x1 + step->xoffs; |
| 1593 | vertex[1].y = b0.y1 + step->yoffs; |
| 1594 | |
| 1595 | // rotate the unit vector by 45 degrees and add to point 1 |
| 1596 | vertex[2].x = b1.x0 + step->xoffs; |
| 1597 | vertex[2].y = b1.y0 + step->yoffs; |
| 1598 | |
| 1599 | // rotate the unit vector by -45 degrees and add to point 1 |
| 1600 | vertex[3].x = b1.x1 + step->xoffs; |
| 1601 | vertex[3].y = b1.y1 + step->yoffs; |
| 1602 | |
| 1603 | // determine the color of the line |
| 1604 | INT32 r = (INT32)(prim->color.r * step->weight * 255.0f); |
| 1605 | INT32 g = (INT32)(prim->color.g * step->weight * 255.0f); |
| 1606 | INT32 b = (INT32)(prim->color.b * step->weight * 255.0f); |
| 1607 | INT32 a = (INT32)(prim->color.a * 255.0f); |
| 1608 | if (r > 255) r = 255; |
| 1609 | if (g > 255) g = 255; |
| 1610 | if (b > 255) b = 255; |
| 1611 | if (a > 255) a = 255; |
| 1612 | DWORD color = D3DCOLOR_ARGB(a, r, g, b); |
| 1613 | |
| 1614 | vec2f& start = (get_vector_texture() ? get_vector_texture()->get_uvstart() : get_default_texture()->get_uvstart()); |
| 1615 | vec2f& stop = (get_vector_texture() ? get_vector_texture()->get_uvstop() : get_default_texture()->get_uvstop()); |
| 1616 | |
| 1617 | vertex[0].u0 = start.c.x; |
| 1618 | vertex[0].v0 = start.c.y; |
| 1619 | |
| 1620 | vertex[2].u0 = stop.c.x; |
| 1621 | vertex[2].v0 = start.c.y; |
| 1622 | |
| 1623 | vertex[1].u0 = start.c.x; |
| 1624 | vertex[1].v0 = stop.c.y; |
| 1625 | |
| 1626 | vertex[3].u0 = stop.c.x; |
| 1627 | vertex[3].v0 = stop.c.y; |
| 1628 | |
| 1629 | // set the color, Z parameters to standard values |
| 1630 | for (int i = 0; i < 4; i++) |
| 1631 | { |
| 1632 | vertex[i].z = 0.0f; |
| 1633 | vertex[i].rhw = 1.0f; |
| 1634 | vertex[i].color = color; |
| 1635 | } |
| 1636 | |
| 1637 | // now add a polygon entry |
| 1638 | m_poly[m_numpolys].init(D3DPT_TRIANGLESTRIP, 2, 4, prim->flags, get_vector_texture(), |
| 1639 | D3DTOP_MODULATE, 0.0f, 1.0f, 0.0f, 0.0f); |
| 1640 | m_numpolys++; |
| 1641 | } |
| 1642 | } |
| 1643 | |
| 1644 | |
| 1645 | //============================================================ |
| 1646 | // draw_quad |
| 1647 | //============================================================ |
| 1648 | |
| 1649 | void renderer::draw_quad(const render_primitive *prim) |
| 1650 | { |
| 1651 | texture_info *texture = m_texture_manager->find_texinfo(&prim->texture, prim->flags); |
| 1652 | |
| 1653 | if (texture == NULL) |
| 1654 | { |
| 1655 | texture = get_default_texture(); |
| 1656 | } |
| 1657 | |
| 1658 | // get a pointer to the vertex buffer |
| 1659 | vertex *vertex = mesh_alloc(4); |
| 1660 | if (vertex == NULL) |
| 1661 | return; |
| 1662 | |
| 1663 | // fill in the vertexes clockwise |
| 1664 | vertex[0].x = prim->bounds.x0; |
| 1665 | vertex[0].y = prim->bounds.y0; |
| 1666 | vertex[1].x = prim->bounds.x1; |
| 1667 | vertex[1].y = prim->bounds.y0; |
| 1668 | vertex[2].x = prim->bounds.x0; |
| 1669 | vertex[2].y = prim->bounds.y1; |
| 1670 | vertex[3].x = prim->bounds.x1; |
| 1671 | vertex[3].y = prim->bounds.y1; |
| 1672 | float width = prim->bounds.x1 - prim->bounds.x0; |
| 1673 | float height = prim->bounds.y1 - prim->bounds.y0; |
| 1674 | |
| 1675 | // set the texture coordinates |
| 1676 | if(texture != NULL) |
| 1677 | { |
| 1678 | vec2f& start = texture->get_uvstart(); |
| 1679 | vec2f& stop = texture->get_uvstop(); |
| 1680 | vec2f delta = stop - start; |
| 1681 | vertex[0].u0 = start.c.x + delta.c.x * prim->texcoords.tl.u; |
| 1682 | vertex[0].v0 = start.c.y + delta.c.y * prim->texcoords.tl.v; |
| 1683 | vertex[1].u0 = start.c.x + delta.c.x * prim->texcoords.tr.u; |
| 1684 | vertex[1].v0 = start.c.y + delta.c.y * prim->texcoords.tr.v; |
| 1685 | vertex[2].u0 = start.c.x + delta.c.x * prim->texcoords.bl.u; |
| 1686 | vertex[2].v0 = start.c.y + delta.c.y * prim->texcoords.bl.v; |
| 1687 | vertex[3].u0 = start.c.x + delta.c.x * prim->texcoords.br.u; |
| 1688 | vertex[3].v0 = start.c.y + delta.c.y * prim->texcoords.br.v; |
| 1689 | } |
| 1690 | |
| 1691 | // determine the color, allowing for over modulation |
| 1692 | INT32 r = (INT32)(prim->color.r * 255.0f); |
| 1693 | INT32 g = (INT32)(prim->color.g * 255.0f); |
| 1694 | INT32 b = (INT32)(prim->color.b * 255.0f); |
| 1695 | INT32 a = (INT32)(prim->color.a * 255.0f); |
| 1696 | DWORD modmode = D3DTOP_MODULATE; |
| 1697 | if (texture != NULL) |
| 1698 | { |
| 1699 | if (m_mod2x_supported && (r > 255 || g > 255 || b > 255)) |
| 1700 | { |
| 1701 | if (m_mod4x_supported && (r > 2*255 || g > 2*255 || b > 2*255)) |
| 1702 | { |
| 1703 | r >>= 2; g >>= 2; b >>= 2; |
| 1704 | modmode = D3DTOP_MODULATE4X; |
| 1705 | } |
| 1706 | else |
| 1707 | { |
| 1708 | r >>= 1; g >>= 1; b >>= 1; |
| 1709 | modmode = D3DTOP_MODULATE2X; |
| 1710 | } |
| 1711 | } |
| 1712 | } |
| 1713 | if (r > 255) r = 255; |
| 1714 | if (g > 255) g = 255; |
| 1715 | if (b > 255) b = 255; |
| 1716 | if (a > 255) a = 255; |
| 1717 | DWORD color = D3DCOLOR_ARGB(a, r, g, b); |
| 1718 | |
| 1719 | // adjust half pixel X/Y offset, set the color, Z parameters to standard values |
| 1720 | for (int i = 0; i < 4; i++) |
| 1721 | { |
| 1722 | vertex[i].x -= 0.5f; |
| 1723 | vertex[i].y -= 0.5f; |
| 1724 | vertex[i].z = 0.0f; |
| 1725 | vertex[i].rhw = 1.0f; |
| 1726 | vertex[i].color = color; |
| 1727 | } |
| 1728 | |
| 1729 | // now add a polygon entry |
| 1730 | m_poly[m_numpolys].init(D3DPT_TRIANGLESTRIP, 2, 4, prim->flags, texture, modmode, width, height); |
| 1731 | m_numpolys++; |
| 1732 | } |
| 1733 | |
| 1734 | void poly_info::init(D3DPRIMITIVETYPE type, UINT32 count, UINT32 numverts, |
| 1735 | UINT32 flags, texture_info *texture, UINT32 modmode, |
| 1736 | float line_time, float line_length, |
| 1737 | float prim_width, float prim_height) |
| 1738 | { |
| 1739 | init(type, count, numverts, flags, texture, modmode, prim_width, prim_height); |
| 1740 | m_line_time = line_time; |
| 1741 | m_line_length = line_length; |
| 1742 | } |
| 1743 | |
| 1744 | void poly_info::init(D3DPRIMITIVETYPE type, UINT32 count, UINT32 numverts, |
| 1745 | UINT32 flags, texture_info *texture, UINT32 modmode, |
| 1746 | float prim_width, float prim_height) |
| 1747 | { |
| 1748 | m_type = type; |
| 1749 | m_count = count; |
| 1750 | m_numverts = numverts; |
| 1751 | m_flags = flags; |
| 1752 | m_texture = texture; |
| 1753 | m_modmode = modmode; |
| 1754 | m_prim_width = prim_width; |
| 1755 | m_prim_height = prim_height; |
| 1756 | } |
| 1757 | |
| 1758 | |
| 1759 | //============================================================ |
| 1760 | // primitive_alloc |
| 1761 | //============================================================ |
| 1762 | |
| 1763 | vertex *renderer::mesh_alloc(int numverts) |
| 1764 | { |
| 1765 | HRESULT result; |
| 1766 | |
| 1767 | // if we're going to overflow, flush |
| 1768 | if (m_lockedbuf != NULL && m_numverts + numverts >= VERTEX_BUFFER_SIZE) |
| 1769 | { |
| 1770 | primitive_flush_pending(); |
| 1771 | |
| 1772 | if(m_shaders->enabled()) |
| 1773 | { |
| 1774 | m_hlsl_buf = (void*)mesh_alloc(6); |
| 1775 | m_shaders->init_fsfx_quad(m_hlsl_buf); |
| 1776 | } |
| 1777 | } |
| 1778 | |
| 1779 | // if we don't have a lock, grab it now |
| 1780 | if (m_lockedbuf == NULL) |
| 1781 | { |
| 1782 | result = (*d3dintf->vertexbuf.lock)(m_vertexbuf, 0, 0, (VOID **)&m_lockedbuf, D3DLOCK_DISCARD); |
| 1783 | if (result != D3D_OK) |
| 1784 | return NULL; |
| 1785 | } |
| 1786 | |
| 1787 | // if we already have the lock and enough room, just return a pointer |
| 1788 | if (m_lockedbuf != NULL && m_numverts + numverts < VERTEX_BUFFER_SIZE) |
| 1789 | { |
| 1790 | int oldverts = m_numverts; |
| 1791 | m_numverts += numverts; |
| 1792 | return &m_lockedbuf[oldverts]; |
| 1793 | } |
| 1794 | return NULL; |
| 1795 | } |
| 1796 | |
| 1797 | |
| 1798 | //============================================================ |
| 1799 | // primitive_flush_pending |
| 1800 | //============================================================ |
| 1801 | |
| 1802 | void renderer::primitive_flush_pending() |
| 1803 | { |
| 1804 | // ignore if we're not locked |
| 1805 | if (m_lockedbuf == NULL) |
| 1806 | { |
| 1807 | return; |
| 1808 | } |
| 1809 | |
| 1810 | // unlock the buffer |
| 1811 | HRESULT result = (*d3dintf->vertexbuf.unlock)(m_vertexbuf); |
| 1812 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during vertex buffer unlock call\n", (int)result); |
| 1813 | m_lockedbuf = NULL; |
| 1814 | |
| 1815 | // set the stream |
| 1816 | result = (*d3dintf->device.set_stream_source)(m_device, 0, m_vertexbuf, sizeof(vertex)); |
| 1817 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_stream_source call\n", (int)result); |
| 1818 | |
| 1819 | m_shaders->begin_draw(); |
| 1820 | |
| 1821 | int vertnum = 0; |
| 1822 | if (m_shaders->enabled()) |
| 1823 | { |
| 1824 | vertnum = 6; |
| 1825 | } |
| 1826 | |
| 1827 | // now do the polys |
| 1828 | for (int polynum = 0; polynum < m_numpolys; polynum++) |
| 1829 | { |
| 1830 | UINT32 flags = m_poly[polynum].get_flags(); |
| 1831 | texture_info *texture = m_poly[polynum].get_texture(); |
| 1832 | int newfilter; |
| 1833 | |
| 1834 | // set the texture if different |
| 1835 | set_texture(texture); |
| 1836 | |
| 1837 | // set filtering if different |
| 1838 | if (texture != NULL) |
| 1839 | { |
| 1840 | newfilter = FALSE; |
| 1841 | if (PRIMFLAG_GET_SCREENTEX(flags)) |
| 1842 | newfilter = video_config.filter; |
| 1843 | set_filter(newfilter); |
| 1844 | set_wrap(PRIMFLAG_GET_TEXWRAP(flags) ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP); |
| 1845 | set_modmode(m_poly[polynum].get_modmode()); |
| 1846 | |
| 1847 | m_shaders->init_effect_info(&m_poly[polynum]); |
| 1848 | } |
| 1849 | |
| 1850 | // set the blendmode if different |
| 1851 | set_blendmode(PRIMFLAG_GET_BLENDMODE(flags)); |
| 1852 | |
| 1853 | if (vertnum + m_poly[polynum].get_vertcount() > m_numverts) |
| 1854 | { |
| 1855 | osd_printf_error("Error: vertnum (%d) plus poly vertex count (%d) > %d\n", vertnum, m_poly[polynum].get_vertcount(), m_numverts); |
| 1856 | fflush(stdout); |
| 1857 | } |
| 1858 | |
| 1859 | assert(vertnum + m_poly[polynum].get_vertcount() <= m_numverts); |
| 1860 | |
| 1861 | if(m_shaders->enabled() && d3dintf->post_fx_available) |
| 1862 | { |
| 1863 | m_shaders->render_quad(&m_poly[polynum], vertnum); |
| 1864 | } |
| 1865 | else |
| 1866 | { |
| 1867 | // add the primitives |
| 1868 | result = (*d3dintf->device.draw_primitive)(m_device, m_poly[polynum].get_type(), vertnum, |
| 1869 | m_poly[polynum].get_count()); |
| 1870 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device draw_primitive call\n", (int)result); |
| 1871 | } |
| 1872 | |
| 1873 | vertnum += m_poly[polynum].get_vertcount(); |
| 1874 | } |
| 1875 | |
| 1876 | m_shaders->end_draw(); |
| 1877 | |
| 1878 | // reset the vertex count |
| 1879 | m_numverts = 0; |
| 1880 | m_numpolys = 0; |
| 1881 | } |
| 1882 | |
| 1883 | |
| 1884 | //============================================================ |
| 1885 | // texture_info destructor |
| 1886 | //============================================================ |
| 1887 | |
| 1888 | texture_info::~texture_info() |
| 1889 | { |
| 1890 | if (m_d3dfinaltex != NULL) |
| 1891 | { |
| 1892 | if (m_d3dtex == m_d3dfinaltex) |
| 1893 | { |
| 1894 | m_d3dtex = NULL; |
| 1895 | } |
| 1896 | (*d3dintf->texture.release)(m_d3dfinaltex); |
| 1897 | m_d3dfinaltex = NULL; |
| 1898 | } |
| 1899 | if (m_d3dtex != NULL) |
| 1900 | { |
| 1901 | (*d3dintf->texture.release)(m_d3dtex); |
| 1902 | m_d3dtex = NULL; |
| 1903 | } |
| 1904 | if (m_d3dsurface != NULL) |
| 1905 | { |
| 1906 | (*d3dintf->surface.release)(m_d3dsurface); |
| 1907 | m_d3dsurface = NULL; |
| 1908 | } |
| 1909 | } |
| 1910 | |
| 1911 | |
| 1912 | //============================================================ |
| 1913 | // texture_info constructor |
| 1914 | //============================================================ |
| 1915 | |
| 1916 | texture_info::texture_info(texture_manager *manager, const render_texinfo* texsource, int prescale, UINT32 flags) |
| 1917 | { |
| 1918 | HRESULT result; |
| 1919 | |
| 1920 | // fill in the core data |
| 1921 | m_texture_manager = manager; |
| 1922 | m_renderer = m_texture_manager->get_d3d(); |
| 1923 | m_hash = m_texture_manager->texture_compute_hash(texsource, flags); |
| 1924 | m_flags = flags; |
| 1925 | m_texinfo = *texsource; |
| 1926 | m_xprescale = prescale; |
| 1927 | m_yprescale = prescale; |
| 1928 | |
| 1929 | m_d3dtex = NULL; |
| 1930 | m_d3dsurface = NULL; |
| 1931 | m_d3dfinaltex = NULL; |
| 1932 | |
| 1933 | // compute the size |
| 1934 | compute_size(texsource->width, texsource->height); |
| 1935 | |
| 1936 | // non-screen textures are easy |
| 1937 | if (!PRIMFLAG_GET_SCREENTEX(flags)) |
| 1938 | { |
| 1939 | assert(PRIMFLAG_TEXFORMAT(flags) != TEXFORMAT_YUY16); |
| 1940 | result = (*d3dintf->device.create_texture)(m_renderer->get_device(), m_rawdims.c.x, m_rawdims.c.y, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_d3dtex); |
| 1941 | if (result != D3D_OK) |
| 1942 | goto error; |
| 1943 | m_d3dfinaltex = m_d3dtex; |
| 1944 | m_type = TEXTURE_TYPE_PLAIN; |
| 1945 | } |
| 1946 | |
| 1947 | // screen textures are allocated differently |
| 1948 | else |
| 1949 | { |
| 1950 | D3DFORMAT format; |
| 1951 | DWORD usage = m_texture_manager->is_dynamic_supported() ? D3DUSAGE_DYNAMIC : 0; |
| 1952 | D3DPOOL pool = m_texture_manager->is_dynamic_supported() ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED; |
| 1953 | int maxdim = MAX(m_renderer->get_presentation()->BackBufferWidth, m_renderer->get_presentation()->BackBufferHeight); |
| 1954 | |
| 1955 | // pick the format |
| 1956 | if (PRIMFLAG_GET_TEXFORMAT(flags) == TEXFORMAT_YUY16) |
| 1957 | { |
| 1958 | format = m_texture_manager->get_yuv_format(); |
| 1959 | } |
| 1960 | else if (PRIMFLAG_GET_TEXFORMAT(flags) == TEXFORMAT_ARGB32 || PRIMFLAG_GET_TEXFORMAT(flags) == TEXFORMAT_PALETTEA16) |
| 1961 | { |
| 1962 | format = D3DFMT_A8R8G8B8; |
| 1963 | } |
| 1964 | else |
| 1965 | { |
| 1966 | format = m_renderer->get_screen_format(); |
| 1967 | } |
| 1968 | |
| 1969 | // don't prescale above screen size |
| 1970 | while (m_xprescale > 1 && m_rawdims.c.x * m_xprescale >= 2 * maxdim) |
| 1971 | { |
| 1972 | m_xprescale--; |
| 1973 | } |
| 1974 | while (m_xprescale > 1 && m_rawdims.c.x * m_xprescale > manager->get_max_texture_width()) |
| 1975 | { |
| 1976 | m_xprescale--; |
| 1977 | } |
| 1978 | while (m_yprescale > 1 && m_rawdims.c.y * m_yprescale >= 2 * maxdim) |
| 1979 | { |
| 1980 | m_yprescale--; |
| 1981 | } |
| 1982 | while (m_yprescale > 1 && m_rawdims.c.y * m_yprescale > manager->get_max_texture_height()) |
| 1983 | { |
| 1984 | m_yprescale--; |
| 1985 | } |
| 1986 | |
| 1987 | int prescale = m_renderer->window().prescale(); |
| 1988 | if (m_xprescale != prescale || m_yprescale != prescale) |
| 1989 | { |
| 1990 | osd_printf_verbose("Direct3D: adjusting prescale from %dx%d to %dx%d\n", prescale, prescale, m_xprescale, m_yprescale); |
| 1991 | } |
| 1992 | |
| 1993 | // loop until we allocate something or error |
| 1994 | for (int attempt = 0; attempt < 2; attempt++) |
| 1995 | { |
| 1996 | // second attempt is always 1:1 |
| 1997 | if (attempt == 1) |
| 1998 | { |
| 1999 | m_xprescale = m_yprescale = 1; |
| 2000 | } |
| 2001 | |
| 2002 | // screen textures with no prescaling are pretty easy |
| 2003 | if (m_xprescale == 1 && m_yprescale == 1) |
| 2004 | { |
| 2005 | result = (*d3dintf->device.create_texture)(m_renderer->get_device(), m_rawdims.c.x, m_rawdims.c.y, 1, usage, format, pool, &m_d3dtex); |
| 2006 | if (result == D3D_OK) |
| 2007 | { |
| 2008 | m_d3dfinaltex = m_d3dtex; |
| 2009 | m_type = m_texture_manager->is_dynamic_supported() ? TEXTURE_TYPE_DYNAMIC : TEXTURE_TYPE_PLAIN; |
| 2010 | if (m_renderer->get_shaders()->enabled() && !m_renderer->get_shaders()->register_texture(this)) |
| 2011 | { |
| 2012 | goto error; |
| 2013 | } |
| 2014 | |
| 2015 | break; |
| 2016 | } |
| 2017 | } |
| 2018 | |
| 2019 | // screen textures with prescaling require two allocations |
| 2020 | else |
| 2021 | { |
| 2022 | // use an offscreen plain surface for stretching if supported |
| 2023 | // (won't work for YUY textures) |
| 2024 | if (m_texture_manager->is_stretch_supported() && PRIMFLAG_GET_TEXFORMAT(flags) != TEXFORMAT_YUY16) |
| 2025 | { |
| 2026 | result = (*d3dintf->device.create_offscreen_plain_surface)(m_renderer->get_device(), m_rawdims.c.x, m_rawdims.c.y, format, D3DPOOL_DEFAULT, &m_d3dsurface); |
| 2027 | if (result != D3D_OK) |
| 2028 | { |
| 2029 | continue; |
| 2030 | } |
| 2031 | m_type = TEXTURE_TYPE_SURFACE; |
| 2032 | } |
| 2033 | |
| 2034 | // otherwise, we allocate a dynamic texture for the source |
| 2035 | else |
| 2036 | { |
| 2037 | result = (*d3dintf->device.create_texture)(m_renderer->get_device(), m_rawdims.c.x, m_rawdims.c.y, 1, usage, format, pool, &m_d3dtex); |
| 2038 | if (result != D3D_OK) |
| 2039 | { |
| 2040 | continue; |
| 2041 | } |
| 2042 | m_type = m_texture_manager->is_dynamic_supported() ? TEXTURE_TYPE_DYNAMIC : TEXTURE_TYPE_PLAIN; |
| 2043 | } |
| 2044 | |
| 2045 | // for the target surface, we allocate a render target texture |
| 2046 | int scwidth = m_rawdims.c.x * m_xprescale; |
| 2047 | int scheight = m_rawdims.c.y * m_yprescale; |
| 2048 | |
| 2049 | // target surfaces typically cannot be YCbCr, so we always pick RGB in that case |
| 2050 | D3DFORMAT finalfmt = (format != m_texture_manager->get_yuv_format()) ? format : D3DFMT_A8R8G8B8; |
| 2051 | result = (*d3dintf->device.create_texture)(m_renderer->get_device(), scwidth, scheight, 1, D3DUSAGE_RENDERTARGET, finalfmt, D3DPOOL_DEFAULT, &m_d3dfinaltex); |
| 2052 | if (result == D3D_OK) |
| 2053 | { |
| 2054 | if (m_renderer->get_shaders()->enabled() && !m_renderer->get_shaders()->register_prescaled_texture(this)) |
| 2055 | { |
| 2056 | goto error; |
| 2057 | } |
| 2058 | break; |
| 2059 | } |
| 2060 | (*d3dintf->texture.release)(m_d3dtex); |
| 2061 | m_d3dtex = NULL; |
| 2062 | } |
| 2063 | } |
| 2064 | } |
| 2065 | |
| 2066 | // copy the data to the texture |
| 2067 | set_data(texsource, flags); |
| 2068 | |
| 2069 | //texsource->osdhandle = (void*)this; |
| 2070 | // add us to the texture list |
| 2071 | if(m_texture_manager->get_texlist() != NULL) |
| 2072 | m_texture_manager->get_texlist()->m_prev = this; |
| 2073 | m_prev = NULL; |
| 2074 | m_next = m_texture_manager->get_texlist(); |
| 2075 | m_texture_manager->set_texlist(this); |
| 2076 | return; |
| 2077 | |
| 2078 | error: |
| 2079 | d3dintf->post_fx_available = false; |
| 2080 | osd_printf_error("Direct3D: Critical warning: A texture failed to allocate. Expect things to get bad quickly.\n"); |
| 2081 | if (m_d3dsurface != NULL) |
| 2082 | (*d3dintf->surface.release)(m_d3dsurface); |
| 2083 | if (m_d3dtex != NULL) |
| 2084 | (*d3dintf->texture.release)(m_d3dtex); |
| 2085 | } |
| 2086 | |
| 2087 | |
| 2088 | //============================================================ |
| 2089 | // texture_info::compute_size_subroutine |
| 2090 | //============================================================ |
| 2091 | |
| 2092 | void texture_info::compute_size_subroutine(int texwidth, int texheight, int* p_width, int* p_height) |
| 2093 | { |
| 2094 | int finalheight = texheight; |
| 2095 | int finalwidth = texwidth; |
| 2096 | |
| 2097 | // round width/height up to nearest power of 2 if we need to |
| 2098 | if (!(m_texture_manager->get_texture_caps() & D3DPTEXTURECAPS_NONPOW2CONDITIONAL)) |
| 2099 | { |
| 2100 | // first the width |
| 2101 | if (finalwidth & (finalwidth - 1)) |
| 2102 | { |
| 2103 | finalwidth |= finalwidth >> 1; |
| 2104 | finalwidth |= finalwidth >> 2; |
| 2105 | finalwidth |= finalwidth >> 4; |
| 2106 | finalwidth |= finalwidth >> 8; |
| 2107 | finalwidth++; |
| 2108 | } |
| 2109 | |
| 2110 | // then the height |
| 2111 | if (finalheight & (finalheight - 1)) |
| 2112 | { |
| 2113 | finalheight |= finalheight >> 1; |
| 2114 | finalheight |= finalheight >> 2; |
| 2115 | finalheight |= finalheight >> 4; |
| 2116 | finalheight |= finalheight >> 8; |
| 2117 | finalheight++; |
| 2118 | } |
| 2119 | } |
| 2120 | |
| 2121 | // round up to square if we need to |
| 2122 | if (m_texture_manager->get_texture_caps() & D3DPTEXTURECAPS_SQUAREONLY) |
| 2123 | { |
| 2124 | if (finalwidth < finalheight) |
| 2125 | finalwidth = finalheight; |
| 2126 | else |
| 2127 | finalheight = finalwidth; |
| 2128 | } |
| 2129 | |
| 2130 | // adjust the aspect ratio if we need to |
| 2131 | while (finalwidth < finalheight && finalheight / finalwidth > m_texture_manager->get_max_texture_aspect()) |
| 2132 | { |
| 2133 | finalwidth *= 2; |
| 2134 | } |
| 2135 | while (finalheight < finalwidth && finalwidth / finalheight > m_texture_manager->get_max_texture_aspect()) |
| 2136 | { |
| 2137 | finalheight *= 2; |
| 2138 | } |
| 2139 | |
| 2140 | *p_width = finalwidth; |
| 2141 | *p_height = finalheight; |
| 2142 | } |
| 2143 | |
| 2144 | |
| 2145 | //============================================================ |
| 2146 | // texture_info::compute_size |
| 2147 | //============================================================ |
| 2148 | |
| 2149 | void texture_info::compute_size(int texwidth, int texheight) |
| 2150 | { |
| 2151 | int finalheight = texheight; |
| 2152 | int finalwidth = texwidth; |
| 2153 | |
| 2154 | m_xborderpix = 0; |
| 2155 | m_yborderpix = 0; |
| 2156 | |
| 2157 | // if we're not wrapping, add a 1-2 pixel border on all sides |
| 2158 | if (ENABLE_BORDER_PIX && !(m_flags & PRIMFLAG_TEXWRAP_MASK)) |
| 2159 | { |
| 2160 | // note we need 2 pixels in X for YUY textures |
| 2161 | m_xborderpix = (PRIMFLAG_GET_TEXFORMAT(m_flags) == TEXFORMAT_YUY16) ? 2 : 1; |
| 2162 | m_yborderpix = 1; |
| 2163 | } |
| 2164 | |
| 2165 | // compute final texture size |
| 2166 | finalwidth += 2 * m_xborderpix; |
| 2167 | finalheight += 2 * m_yborderpix; |
| 2168 | |
| 2169 | compute_size_subroutine(finalwidth, finalheight, &finalwidth, &finalheight); |
| 2170 | |
| 2171 | // if we added pixels for the border, and that just barely pushed us over, take it back |
| 2172 | if (finalwidth > m_texture_manager->get_max_texture_width() || finalheight > m_texture_manager->get_max_texture_height()) |
| 2173 | { |
| 2174 | finalheight = texheight; |
| 2175 | finalwidth = texwidth; |
| 2176 | |
| 2177 | m_xborderpix = 0; |
| 2178 | m_yborderpix = 0; |
| 2179 | |
| 2180 | compute_size_subroutine(finalwidth, finalheight, &finalwidth, &finalheight); |
| 2181 | } |
| 2182 | |
| 2183 | // if we're above the max width/height, do what? |
| 2184 | if (finalwidth > m_texture_manager->get_max_texture_width() || finalheight > m_texture_manager->get_max_texture_height()) |
| 2185 | { |
| 2186 | static int printed = FALSE; |
| 2187 | if (!printed) osd_printf_warning("Texture too big! (wanted: %dx%d, max is %dx%d)\n", finalwidth, finalheight, (int)m_texture_manager->get_max_texture_width(), (int)m_texture_manager->get_max_texture_height()); |
| 2188 | printed = TRUE; |
| 2189 | } |
| 2190 | |
| 2191 | // compute the U/V scale factors |
| 2192 | m_start.c.x = (float)m_xborderpix / (float)finalwidth; |
| 2193 | m_start.c.y = (float)m_yborderpix / (float)finalheight; |
| 2194 | m_stop.c.x = (float)(texwidth + m_xborderpix) / (float)finalwidth; |
| 2195 | m_stop.c.y = (float)(texheight + m_yborderpix) / (float)finalheight; |
| 2196 | |
| 2197 | // set the final values |
| 2198 | m_rawdims.c.x = finalwidth; |
| 2199 | m_rawdims.c.y = finalheight; |
| 2200 | } |
| 2201 | |
| 2202 | |
| 2203 | //============================================================ |
| 2204 | // copyline_palette16 |
| 2205 | //============================================================ |
| 2206 | |
| 2207 | INLINE void copyline_palette16(UINT32 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix) |
| 2208 | { |
| 2209 | int x; |
| 2210 | |
| 2211 | assert(xborderpix == 0 || xborderpix == 1); |
| 2212 | if (xborderpix) |
| 2213 | *dst++ = 0xff000000 | palette[*src]; |
| 2214 | for (x = 0; x < width; x++) |
| 2215 | *dst++ = 0xff000000 | palette[*src++]; |
| 2216 | if (xborderpix) |
| 2217 | *dst++ = 0xff000000 | palette[*--src]; |
| 2218 | } |
| 2219 | |
| 2220 | |
| 2221 | //============================================================ |
| 2222 | // copyline_palettea16 |
| 2223 | //============================================================ |
| 2224 | |
| 2225 | INLINE void copyline_palettea16(UINT32 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix) |
| 2226 | { |
| 2227 | int x; |
| 2228 | |
| 2229 | assert(xborderpix == 0 || xborderpix == 1); |
| 2230 | if (xborderpix) |
| 2231 | *dst++ = palette[*src]; |
| 2232 | for (x = 0; x < width; x++) |
| 2233 | *dst++ = palette[*src++]; |
| 2234 | if (xborderpix) |
| 2235 | *dst++ = palette[*--src]; |
| 2236 | } |
| 2237 | |
| 2238 | |
| 2239 | //============================================================ |
| 2240 | // copyline_rgb32 |
| 2241 | //============================================================ |
| 2242 | |
| 2243 | INLINE void copyline_rgb32(UINT32 *dst, const UINT32 *src, int width, const rgb_t *palette, int xborderpix) |
| 2244 | { |
| 2245 | int x; |
| 2246 | |
| 2247 | assert(xborderpix == 0 || xborderpix == 1); |
| 2248 | |
| 2249 | // palette (really RGB map) case |
| 2250 | if (palette != NULL) |
| 2251 | { |
| 2252 | if (xborderpix) |
| 2253 | { |
| 2254 | rgb_t srcpix = *src; |
| 2255 | *dst++ = 0xff000000 | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()]; |
| 2256 | } |
| 2257 | for (x = 0; x < width; x++) |
| 2258 | { |
| 2259 | rgb_t srcpix = *src++; |
| 2260 | *dst++ = 0xff000000 | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()]; |
| 2261 | } |
| 2262 | if (xborderpix) |
| 2263 | { |
| 2264 | rgb_t srcpix = *--src; |
| 2265 | *dst++ = 0xff000000 | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()]; |
| 2266 | } |
| 2267 | } |
| 2268 | |
| 2269 | // direct case |
| 2270 | else |
| 2271 | { |
| 2272 | if (xborderpix) |
| 2273 | *dst++ = 0xff000000 | *src; |
| 2274 | for (x = 0; x < width; x++) |
| 2275 | *dst++ = 0xff000000 | *src++; |
| 2276 | if (xborderpix) |
| 2277 | *dst++ = 0xff000000 | *--src; |
| 2278 | } |
| 2279 | } |
| 2280 | |
| 2281 | |
| 2282 | //============================================================ |
| 2283 | // copyline_argb32 |
| 2284 | //============================================================ |
| 2285 | |
| 2286 | INLINE void copyline_argb32(UINT32 *dst, const UINT32 *src, int width, const rgb_t *palette, int xborderpix) |
| 2287 | { |
| 2288 | int x; |
| 2289 | |
| 2290 | assert(xborderpix == 0 || xborderpix == 1); |
| 2291 | |
| 2292 | // palette (really RGB map) case |
| 2293 | if (palette != NULL) |
| 2294 | { |
| 2295 | if (xborderpix) |
| 2296 | { |
| 2297 | rgb_t srcpix = *src; |
| 2298 | *dst++ = (srcpix & 0xff000000) | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()]; |
| 2299 | } |
| 2300 | for (x = 0; x < width; x++) |
| 2301 | { |
| 2302 | rgb_t srcpix = *src++; |
| 2303 | *dst++ = (srcpix & 0xff000000) | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()]; |
| 2304 | } |
| 2305 | if (xborderpix) |
| 2306 | { |
| 2307 | rgb_t srcpix = *--src; |
| 2308 | *dst++ = (srcpix & 0xff000000) | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()]; |
| 2309 | } |
| 2310 | } |
| 2311 | |
| 2312 | // direct case |
| 2313 | else |
| 2314 | { |
| 2315 | if (xborderpix) |
| 2316 | *dst++ = *src; |
| 2317 | for (x = 0; x < width; x++) |
| 2318 | *dst++ = *src++; |
| 2319 | if (xborderpix) |
| 2320 | *dst++ = *--src; |
| 2321 | } |
| 2322 | } |
| 2323 | |
| 2324 | |
| 2325 | //============================================================ |
| 2326 | // copyline_yuy16_to_yuy2 |
| 2327 | //============================================================ |
| 2328 | |
| 2329 | INLINE void copyline_yuy16_to_yuy2(UINT16 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix) |
| 2330 | { |
| 2331 | int x; |
| 2332 | |
| 2333 | assert(xborderpix == 0 || xborderpix == 2); |
| 2334 | assert(width % 2 == 0); |
| 2335 | |
| 2336 | // palette (really RGB map) case |
| 2337 | if (palette != NULL) |
| 2338 | { |
| 2339 | if (xborderpix) |
| 2340 | { |
| 2341 | UINT16 srcpix0 = *src++; |
| 2342 | UINT16 srcpix1 = *src--; |
| 2343 | *dst++ = palette[0x000 + (srcpix0 >> 8)] | (srcpix0 << 8); |
| 2344 | *dst++ = palette[0x000 + (srcpix0 >> 8)] | (srcpix1 << 8); |
| 2345 | } |
| 2346 | for (x = 0; x < width; x += 2) |
| 2347 | { |
| 2348 | UINT16 srcpix0 = *src++; |
| 2349 | UINT16 srcpix1 = *src++; |
| 2350 | *dst++ = palette[0x000 + (srcpix0 >> 8)] | (srcpix0 << 8); |
| 2351 | *dst++ = palette[0x000 + (srcpix1 >> 8)] | (srcpix1 << 8); |
| 2352 | } |
| 2353 | if (xborderpix) |
| 2354 | { |
| 2355 | UINT16 srcpix1 = *--src; |
| 2356 | UINT16 srcpix0 = *--src; |
| 2357 | *dst++ = palette[0x000 + (srcpix1 >> 8)] | (srcpix0 << 8); |
| 2358 | *dst++ = palette[0x000 + (srcpix1 >> 8)] | (srcpix1 << 8); |
| 2359 | } |
| 2360 | } |
| 2361 | |
| 2362 | // direct case |
| 2363 | else |
| 2364 | { |
| 2365 | if (xborderpix) |
| 2366 | { |
| 2367 | UINT16 srcpix0 = *src++; |
| 2368 | UINT16 srcpix1 = *src--; |
| 2369 | *dst++ = (srcpix0 >> 8) | (srcpix0 << 8); |
| 2370 | *dst++ = (srcpix0 >> 8) | (srcpix1 << 8); |
| 2371 | } |
| 2372 | for (x = 0; x < width; x += 2) |
| 2373 | { |
| 2374 | UINT16 srcpix0 = *src++; |
| 2375 | UINT16 srcpix1 = *src++; |
| 2376 | *dst++ = (srcpix0 >> 8) | (srcpix0 << 8); |
| 2377 | *dst++ = (srcpix1 >> 8) | (srcpix1 << 8); |
| 2378 | } |
| 2379 | if (xborderpix) |
| 2380 | { |
| 2381 | UINT16 srcpix1 = *--src; |
| 2382 | UINT16 srcpix0 = *--src; |
| 2383 | *dst++ = (srcpix1 >> 8) | (srcpix0 << 8); |
| 2384 | *dst++ = (srcpix1 >> 8) | (srcpix1 << 8); |
| 2385 | } |
| 2386 | } |
| 2387 | } |
| 2388 | |
| 2389 | |
| 2390 | //============================================================ |
| 2391 | // copyline_yuy16_to_uyvy |
| 2392 | //============================================================ |
| 2393 | |
| 2394 | INLINE void copyline_yuy16_to_uyvy(UINT16 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix) |
| 2395 | { |
| 2396 | int x; |
| 2397 | |
| 2398 | assert(xborderpix == 0 || xborderpix == 2); |
| 2399 | assert(width % 2 == 0); |
| 2400 | |
| 2401 | // palette (really RGB map) case |
| 2402 | if (palette != NULL) |
| 2403 | { |
| 2404 | if (xborderpix) |
| 2405 | { |
| 2406 | UINT16 srcpix0 = *src++; |
| 2407 | UINT16 srcpix1 = *src--; |
| 2408 | *dst++ = palette[0x100 + (srcpix0 >> 8)] | (srcpix0 & 0xff); |
| 2409 | *dst++ = palette[0x100 + (srcpix0 >> 8)] | (srcpix1 & 0xff); |
| 2410 | } |
| 2411 | for (x = 0; x < width; x += 2) |
| 2412 | { |
| 2413 | UINT16 srcpix0 = *src++; |
| 2414 | UINT16 srcpix1 = *src++; |
| 2415 | *dst++ = palette[0x100 + (srcpix0 >> 8)] | (srcpix0 & 0xff); |
| 2416 | *dst++ = palette[0x100 + (srcpix1 >> 8)] | (srcpix1 & 0xff); |
| 2417 | } |
| 2418 | if (xborderpix) |
| 2419 | { |
| 2420 | UINT16 srcpix1 = *--src; |
| 2421 | UINT16 srcpix0 = *--src; |
| 2422 | *dst++ = palette[0x100 + (srcpix1 >> 8)] | (srcpix0 & 0xff); |
| 2423 | *dst++ = palette[0x100 + (srcpix1 >> 8)] | (srcpix1 & 0xff); |
| 2424 | } |
| 2425 | } |
| 2426 | |
| 2427 | // direct case |
| 2428 | else |
| 2429 | { |
| 2430 | if (xborderpix) |
| 2431 | { |
| 2432 | UINT16 srcpix0 = src[0]; |
| 2433 | UINT16 srcpix1 = src[1]; |
| 2434 | *dst++ = srcpix0; |
| 2435 | *dst++ = (srcpix0 & 0xff00) | (srcpix1 & 0x00ff); |
| 2436 | } |
| 2437 | for (x = 0; x < width; x += 2) |
| 2438 | { |
| 2439 | *dst++ = *src++; |
| 2440 | *dst++ = *src++; |
| 2441 | } |
| 2442 | if (xborderpix) |
| 2443 | { |
| 2444 | UINT16 srcpix1 = *--src; |
| 2445 | UINT16 srcpix0 = *--src; |
| 2446 | *dst++ = (srcpix1 & 0xff00) | (srcpix0 & 0x00ff); |
| 2447 | *dst++ = srcpix1; |
| 2448 | } |
| 2449 | } |
| 2450 | } |
| 2451 | |
| 2452 | |
| 2453 | //============================================================ |
| 2454 | // copyline_yuy16_to_argb |
| 2455 | //============================================================ |
| 2456 | |
| 2457 | INLINE void copyline_yuy16_to_argb(UINT32 *dst, const UINT16 *src, int width, const rgb_t *palette, int xborderpix) |
| 2458 | { |
| 2459 | int x; |
| 2460 | |
| 2461 | assert(xborderpix == 0 || xborderpix == 2); |
| 2462 | assert(width % 2 == 0); |
| 2463 | |
| 2464 | // palette (really RGB map) case |
| 2465 | if (palette != NULL) |
| 2466 | { |
| 2467 | if (xborderpix) |
| 2468 | { |
| 2469 | UINT16 srcpix0 = src[0]; |
| 2470 | UINT16 srcpix1 = src[1]; |
| 2471 | UINT8 cb = srcpix0 & 0xff; |
| 2472 | UINT8 cr = srcpix1 & 0xff; |
| 2473 | *dst++ = ycc_to_rgb(palette[0x000 + (srcpix0 >> 8)], cb, cr); |
| 2474 | *dst++ = ycc_to_rgb(palette[0x000 + (srcpix0 >> 8)], cb, cr); |
| 2475 | } |
| 2476 | for (x = 0; x < width / 2; x++) |
| 2477 | { |
| 2478 | UINT16 srcpix0 = *src++; |
| 2479 | UINT16 srcpix1 = *src++; |
| 2480 | UINT8 cb = srcpix0 & 0xff; |
| 2481 | UINT8 cr = srcpix1 & 0xff; |
| 2482 | *dst++ = ycc_to_rgb(palette[0x000 + (srcpix0 >> 8)], cb, cr); |
| 2483 | *dst++ = ycc_to_rgb(palette[0x000 + (srcpix1 >> 8)], cb, cr); |
| 2484 | } |
| 2485 | if (xborderpix) |
| 2486 | { |
| 2487 | UINT16 srcpix1 = *--src; |
| 2488 | UINT16 srcpix0 = *--src; |
| 2489 | UINT8 cb = srcpix0 & 0xff; |
| 2490 | UINT8 cr = srcpix1 & 0xff; |
| 2491 | *dst++ = ycc_to_rgb(palette[0x000 + (srcpix1 >> 8)], cb, cr); |
| 2492 | *dst++ = ycc_to_rgb(palette[0x000 + (srcpix1 >> 8)], cb, cr); |
| 2493 | } |
| 2494 | } |
| 2495 | |
| 2496 | // direct case |
| 2497 | else |
| 2498 | { |
| 2499 | if (xborderpix) |
| 2500 | { |
| 2501 | UINT16 srcpix0 = src[0]; |
| 2502 | UINT16 srcpix1 = src[1]; |
| 2503 | UINT8 cb = srcpix0 & 0xff; |
| 2504 | UINT8 cr = srcpix1 & 0xff; |
| 2505 | *dst++ = ycc_to_rgb(srcpix0 >> 8, cb, cr); |
| 2506 | *dst++ = ycc_to_rgb(srcpix0 >> 8, cb, cr); |
| 2507 | } |
| 2508 | for (x = 0; x < width; x += 2) |
| 2509 | { |
| 2510 | UINT16 srcpix0 = *src++; |
| 2511 | UINT16 srcpix1 = *src++; |
| 2512 | UINT8 cb = srcpix0 & 0xff; |
| 2513 | UINT8 cr = srcpix1 & 0xff; |
| 2514 | *dst++ = ycc_to_rgb(srcpix0 >> 8, cb, cr); |
| 2515 | *dst++ = ycc_to_rgb(srcpix1 >> 8, cb, cr); |
| 2516 | } |
| 2517 | if (xborderpix) |
| 2518 | { |
| 2519 | UINT16 srcpix1 = *--src; |
| 2520 | UINT16 srcpix0 = *--src; |
| 2521 | UINT8 cb = srcpix0 & 0xff; |
| 2522 | UINT8 cr = srcpix1 & 0xff; |
| 2523 | *dst++ = ycc_to_rgb(srcpix1 >> 8, cb, cr); |
| 2524 | *dst++ = ycc_to_rgb(srcpix1 >> 8, cb, cr); |
| 2525 | } |
| 2526 | } |
| 2527 | } |
| 2528 | |
| 2529 | |
| 2530 | //============================================================ |
| 2531 | // texture_set_data |
| 2532 | //============================================================ |
| 2533 | |
| 2534 | void texture_info::set_data(const render_texinfo *texsource, UINT32 flags) |
| 2535 | { |
| 2536 | D3DLOCKED_RECT rect; |
| 2537 | HRESULT result; |
| 2538 | |
| 2539 | // lock the texture |
| 2540 | switch (m_type) |
| 2541 | { |
| 2542 | default: |
| 2543 | case TEXTURE_TYPE_PLAIN: result = (*d3dintf->texture.lock_rect)(m_d3dtex, 0, &rect, NULL, 0); break; |
| 2544 | case TEXTURE_TYPE_DYNAMIC: result = (*d3dintf->texture.lock_rect)(m_d3dtex, 0, &rect, NULL, D3DLOCK_DISCARD); break; |
| 2545 | case TEXTURE_TYPE_SURFACE: result = (*d3dintf->surface.lock_rect)(m_d3dsurface, &rect, NULL, D3DLOCK_DISCARD); break; |
| 2546 | } |
| 2547 | if (result != D3D_OK) |
| 2548 | { |
| 2549 | return; |
| 2550 | } |
| 2551 | |
| 2552 | // loop over Y |
| 2553 | int miny = 0 - m_yborderpix; |
| 2554 | int maxy = texsource->height + m_yborderpix; |
| 2555 | for (int dsty = miny; dsty < maxy; dsty++) |
| 2556 | { |
| 2557 | int srcy = (dsty < 0) ? 0 : (dsty >= texsource->height) ? texsource->height - 1 : dsty; |
| 2558 | void *dst = (BYTE *)rect.pBits + (dsty + m_yborderpix) * rect.Pitch; |
| 2559 | |
| 2560 | // switch off of the format and |
| 2561 | switch (PRIMFLAG_GET_TEXFORMAT(flags)) |
| 2562 | { |
| 2563 | case TEXFORMAT_PALETTE16: |
| 2564 | copyline_palette16((UINT32 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix); |
| 2565 | break; |
| 2566 | |
| 2567 | case TEXFORMAT_PALETTEA16: |
| 2568 | copyline_palettea16((UINT32 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix); |
| 2569 | break; |
| 2570 | |
| 2571 | case TEXFORMAT_RGB32: |
| 2572 | copyline_rgb32((UINT32 *)dst, (UINT32 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix); |
| 2573 | break; |
| 2574 | |
| 2575 | case TEXFORMAT_ARGB32: |
| 2576 | copyline_argb32((UINT32 *)dst, (UINT32 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix); |
| 2577 | break; |
| 2578 | |
| 2579 | case TEXFORMAT_YUY16: |
| 2580 | if (m_texture_manager->get_yuv_format() == D3DFMT_YUY2) |
| 2581 | copyline_yuy16_to_yuy2((UINT16 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix); |
| 2582 | else if (m_texture_manager->get_yuv_format() == D3DFMT_UYVY) |
| 2583 | copyline_yuy16_to_uyvy((UINT16 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix); |
| 2584 | else |
| 2585 | copyline_yuy16_to_argb((UINT32 *)dst, (UINT16 *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette, m_xborderpix); |
| 2586 | break; |
| 2587 | |
| 2588 | default: |
| 2589 | osd_printf_error("Unknown texture blendmode=%d format=%d\n", PRIMFLAG_GET_BLENDMODE(flags), PRIMFLAG_GET_TEXFORMAT(flags)); |
| 2590 | break; |
| 2591 | } |
| 2592 | } |
| 2593 | |
| 2594 | // unlock |
| 2595 | switch (m_type) |
| 2596 | { |
| 2597 | default: |
| 2598 | case TEXTURE_TYPE_PLAIN: result = (*d3dintf->texture.unlock_rect)(m_d3dtex, 0); break; |
| 2599 | case TEXTURE_TYPE_DYNAMIC: result = (*d3dintf->texture.unlock_rect)(m_d3dtex, 0); break; |
| 2600 | case TEXTURE_TYPE_SURFACE: result = (*d3dintf->surface.unlock_rect)(m_d3dsurface); break; |
| 2601 | } |
| 2602 | if (result != D3D_OK) |
| 2603 | { |
| 2604 | osd_printf_verbose("Direct3D: Error %08X during texture unlock_rect call\n", (int)result); |
| 2605 | } |
| 2606 | |
| 2607 | // prescale |
| 2608 | prescale(); |
| 2609 | } |
| 2610 | |
| 2611 | |
| 2612 | //============================================================ |
| 2613 | // texture_info::prescale |
| 2614 | //============================================================ |
| 2615 | |
| 2616 | void texture_info::prescale() |
| 2617 | { |
| 2618 | surface *scale_surface; |
| 2619 | HRESULT result; |
| 2620 | int i; |
| 2621 | |
| 2622 | // if we don't need to, just skip it |
| 2623 | if (m_d3dtex == m_d3dfinaltex) |
| 2624 | return; |
| 2625 | |
| 2626 | // for all cases, we need to get the surface of the render target |
| 2627 | result = (*d3dintf->texture.get_surface_level)(m_d3dfinaltex, 0, &scale_surface); |
| 2628 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during texture get_surface_level call\n", (int)result); |
| 2629 | |
| 2630 | // if we have an offscreen plain surface, we can just StretchRect to it |
| 2631 | if (m_type == TEXTURE_TYPE_SURFACE) |
| 2632 | { |
| 2633 | assert(m_d3dsurface != NULL); |
| 2634 | |
| 2635 | // set the source bounds |
| 2636 | RECT source; |
| 2637 | source.left = source.top = 0; |
| 2638 | source.right = m_texinfo.width + 2 * m_xborderpix; |
| 2639 | source.bottom = m_texinfo.height + 2 * m_yborderpix; |
| 2640 | |
| 2641 | // set the target bounds |
| 2642 | RECT dest; |
| 2643 | dest = source; |
| 2644 | dest.right *= m_xprescale; |
| 2645 | dest.bottom *= m_yprescale; |
| 2646 | |
| 2647 | // do the stretchrect |
| 2648 | result = (*d3dintf->device.stretch_rect)(m_renderer->get_device(), m_d3dsurface, &source, scale_surface, &dest, D3DTEXF_POINT); |
| 2649 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device stretct_rect call\n", (int)result); |
| 2650 | } |
| 2651 | |
| 2652 | // if we are using a texture render target, we need to do more preparations |
| 2653 | else |
| 2654 | { |
| 2655 | surface *backbuffer; |
| 2656 | |
| 2657 | assert(m_d3dtex != NULL); |
| 2658 | |
| 2659 | // first remember the original render target and set the new one |
| 2660 | result = (*d3dintf->device.get_render_target)(m_renderer->get_device(), 0, &backbuffer); |
| 2661 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device get_render_target call\n", (int)result); |
| 2662 | result = (*d3dintf->device.set_render_target)(m_renderer->get_device(), 0, scale_surface); |
| 2663 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call 1\n", (int)result); |
| 2664 | m_renderer->reset_render_states(); |
| 2665 | |
| 2666 | // start the scene |
| 2667 | result = (*d3dintf->device.begin_scene)(m_renderer->get_device()); |
| 2668 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device begin_scene call\n", (int)result); |
| 2669 | |
| 2670 | // configure the rendering pipeline |
| 2671 | m_renderer->set_filter(FALSE); |
| 2672 | m_renderer->set_blendmode(BLENDMODE_NONE); |
| 2673 | result = (*d3dintf->device.set_texture)(m_renderer->get_device(), 0, m_d3dtex); |
| 2674 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_texture call\n", (int)result); |
| 2675 | |
| 2676 | // lock the vertex buffer |
| 2677 | result = (*d3dintf->vertexbuf.lock)(m_renderer->get_vertex_buffer(), 0, 0, m_renderer->get_locked_buffer_ptr(), D3DLOCK_DISCARD); |
| 2678 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during vertex buffer lock call\n", (int)result); |
| 2679 | |
| 2680 | // configure the X/Y coordinates on the target surface |
| 2681 | vertex *lockedbuf = m_renderer->get_locked_buffer(); |
| 2682 | lockedbuf[0].x = -0.5f; |
| 2683 | lockedbuf[0].y = -0.5f; |
| 2684 | lockedbuf[1].x = (float)((m_texinfo.width + 2 * m_xborderpix) * m_xprescale) - 0.5f; |
| 2685 | lockedbuf[1].y = -0.5f; |
| 2686 | lockedbuf[2].x = -0.5f; |
| 2687 | lockedbuf[2].y = (float)((m_texinfo.height + 2 * m_yborderpix) * m_yprescale) - 0.5f; |
| 2688 | lockedbuf[3].x = (float)((m_texinfo.width + 2 * m_xborderpix) * m_xprescale) - 0.5f; |
| 2689 | lockedbuf[3].y = (float)((m_texinfo.height + 2 * m_yborderpix) * m_yprescale) - 0.5f; |
| 2690 | |
| 2691 | // configure the U/V coordintes on the source texture |
| 2692 | lockedbuf[0].u0 = 0.0f; |
| 2693 | lockedbuf[0].v0 = 0.0f; |
| 2694 | lockedbuf[1].u0 = (float)(m_texinfo.width + 2 * m_xborderpix) / (float)m_rawdims.c.x; |
| 2695 | lockedbuf[1].v0 = 0.0f; |
| 2696 | lockedbuf[2].u0 = 0.0f; |
| 2697 | lockedbuf[2].v0 = (float)(m_texinfo.height + 2 * m_yborderpix) / (float)m_rawdims.c.y; |
| 2698 | lockedbuf[3].u0 = (float)(m_texinfo.width + 2 * m_xborderpix) / (float)m_rawdims.c.x; |
| 2699 | lockedbuf[3].v0 = (float)(m_texinfo.height + 2 * m_yborderpix) / (float)m_rawdims.c.y; |
| 2700 | |
| 2701 | // reset the remaining vertex parameters |
| 2702 | for (i = 0; i < 4; i++) |
| 2703 | { |
| 2704 | lockedbuf[i].z = 0.0f; |
| 2705 | lockedbuf[i].rhw = 1.0f; |
| 2706 | lockedbuf[i].color = D3DCOLOR_ARGB(0xff,0xff,0xff,0xff); |
| 2707 | } |
| 2708 | |
| 2709 | // unlock the vertex buffer |
| 2710 | result = (*d3dintf->vertexbuf.unlock)(m_renderer->get_vertex_buffer()); |
| 2711 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during vertex buffer unlock call\n", (int)result); |
| 2712 | m_renderer->set_locked_buffer(NULL); |
| 2713 | |
| 2714 | // set the stream and draw the triangle strip |
| 2715 | result = (*d3dintf->device.set_stream_source)(m_renderer->get_device(), 0, m_renderer->get_vertex_buffer(), sizeof(vertex)); |
| 2716 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_stream_source call\n", (int)result); |
| 2717 | result = (*d3dintf->device.draw_primitive)(m_renderer->get_device(), D3DPT_TRIANGLESTRIP, 0, 2); |
| 2718 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device draw_primitive call\n", (int)result); |
| 2719 | |
| 2720 | // end the scene |
| 2721 | result = (*d3dintf->device.end_scene)(m_renderer->get_device()); |
| 2722 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device end_scene call\n", (int)result); |
| 2723 | |
| 2724 | // reset the render target and release our reference to the backbuffer |
| 2725 | result = (*d3dintf->device.set_render_target)(m_renderer->get_device(), 0, backbuffer); |
| 2726 | if (result != D3D_OK) osd_printf_verbose("Direct3D: Error %08X during device set_render_target call 2\n", (int)result); |
| 2727 | (*d3dintf->surface.release)(backbuffer); |
| 2728 | m_renderer->reset_render_states(); |
| 2729 | } |
| 2730 | |
| 2731 | // release our reference to the target surface |
| 2732 | (*d3dintf->surface.release)(scale_surface); |
| 2733 | } |
| 2734 | |
| 2735 | |
| 2736 | //============================================================ |
| 2737 | // cache_target::~cache_target |
| 2738 | //============================================================ |
| 2739 | |
| 2740 | cache_target::~cache_target() |
| 2741 | { |
| 2742 | for (int index = 0; index < 11; index++) |
| 2743 | { |
| 2744 | if (bloom_texture[index] != NULL) |
| 2745 | { |
| 2746 | (*d3dintf->texture.release)(bloom_texture[index]); |
| 2747 | bloom_texture[index] = NULL; |
| 2748 | } |
| 2749 | if (bloom_target[index] != NULL) |
| 2750 | { |
| 2751 | (*d3dintf->surface.release)(bloom_target[index]); |
| 2752 | bloom_target[index] = NULL; |
| 2753 | } |
| 2754 | } |
| 2755 | |
| 2756 | if (last_texture != NULL) |
| 2757 | { |
| 2758 | (*d3dintf->texture.release)(last_texture); |
| 2759 | last_texture = NULL; |
| 2760 | } |
| 2761 | if (last_target != NULL) |
| 2762 | { |
| 2763 | (*d3dintf->surface.release)(last_target); |
| 2764 | last_target = NULL; |
| 2765 | } |
| 2766 | } |
| 2767 | |
| 2768 | |
| 2769 | //============================================================ |
| 2770 | // cache_target::init - initializes a target cache |
| 2771 | //============================================================ |
| 2772 | |
| 2773 | bool cache_target::init(renderer *d3d, base *d3dintf, int width, int height, int prescale_x, int prescale_y) |
| 2774 | { |
| 2775 | int bloom_index = 0; |
| 2776 | int bloom_size = (width < height) ? width : height; |
| 2777 | int bloom_width = width; |
| 2778 | int bloom_height = height; |
| 2779 | for (; bloom_size >= 2 && bloom_index < 11; bloom_size >>= 1) |
| 2780 | { |
| 2781 | bloom_width >>= 1; |
| 2782 | bloom_height >>= 1; |
| 2783 | |
| 2784 | HRESULT result = (*d3dintf->device.create_texture)(d3d->get_device(), bloom_width, bloom_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bloom_texture[bloom_index]); |
| 2785 | if (result != D3D_OK) |
| 2786 | { |
| 2787 | return false; |
| 2788 | } |
| 2789 | (*d3dintf->texture.get_surface_level)(bloom_texture[bloom_index], 0, &bloom_target[bloom_index]); |
| 2790 | |
| 2791 | bloom_index++; |
| 2792 | } |
| 2793 | |
| 2794 | HRESULT result = (*d3dintf->device.create_texture)(d3d->get_device(), width * prescale_x, height * prescale_y, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &last_texture); |
| 2795 | if (result != D3D_OK) |
| 2796 | { |
| 2797 | return false; |
| 2798 | } |
| 2799 | (*d3dintf->texture.get_surface_level)(last_texture, 0, &last_target); |
| 2800 | |
| 2801 | target_width = width * prescale_x; |
| 2802 | target_height = height * prescale_y; |
| 2803 | |
| 2804 | return true; |
| 2805 | } |
| 2806 | |
| 2807 | |
| 2808 | //============================================================ |
| 2809 | // render_target::~render_target |
| 2810 | //============================================================ |
| 2811 | |
| 2812 | render_target::~render_target() |
| 2813 | { |
| 2814 | for (int index = 0; index < 11; index++) |
| 2815 | { |
| 2816 | if (bloom_texture[index] != NULL) |
| 2817 | { |
| 2818 | (*d3dintf->texture.release)(bloom_texture[index]); |
| 2819 | bloom_texture[index] = NULL; |
| 2820 | } |
| 2821 | if (bloom_target[index] != NULL) |
| 2822 | { |
| 2823 | (*d3dintf->surface.release)(bloom_target[index]); |
| 2824 | bloom_target[index] = NULL; |
| 2825 | } |
| 2826 | } |
| 2827 | |
| 2828 | for (int index = 0; index < 2; index++) |
| 2829 | { |
| 2830 | if (native_texture[index] != NULL) |
| 2831 | { |
| 2832 | (*d3dintf->texture.release)(native_texture[index]); |
| 2833 | native_texture[index] = NULL; |
| 2834 | } |
| 2835 | if (native_target[index] != NULL) |
| 2836 | { |
| 2837 | (*d3dintf->surface.release)(native_target[index]); |
| 2838 | native_target[index] = NULL; |
| 2839 | } |
| 2840 | if (prescale_texture[index] != NULL) |
| 2841 | { |
| 2842 | (*d3dintf->texture.release)(prescale_texture[index]); |
| 2843 | prescale_texture[index] = NULL; |
| 2844 | } |
| 2845 | if (prescale_target[index] != NULL) |
| 2846 | { |
| 2847 | (*d3dintf->surface.release)(prescale_target[index]); |
| 2848 | prescale_target[index] = NULL; |
| 2849 | } |
| 2850 | } |
| 2851 | } |
| 2852 | |
| 2853 | |
| 2854 | //============================================================ |
| 2855 | // render_target::init - initializes a render target |
| 2856 | //============================================================ |
| 2857 | |
| 2858 | bool render_target::init(renderer *d3d, base *d3dintf, int width, int height, int prescale_x, int prescale_y) |
| 2859 | { |
| 2860 | HRESULT result; |
| 2861 | |
| 2862 | for (int index = 0; index < 2; index++) |
| 2863 | { |
| 2864 | result = (*d3dintf->device.create_texture)(d3d->get_device(), width, height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &native_texture[index]); |
| 2865 | if (result != D3D_OK) |
| 2866 | { |
| 2867 | return false; |
| 2868 | } |
| 2869 | (*d3dintf->texture.get_surface_level)(native_texture[index], 0, &native_target[index]); |
| 2870 | |
| 2871 | result = (*d3dintf->device.create_texture)(d3d->get_device(), width * prescale_x, height * prescale_y, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &prescale_texture[index]); |
| 2872 | if (result != D3D_OK) |
| 2873 | { |
| 2874 | return false; |
| 2875 | } |
| 2876 | (*d3dintf->texture.get_surface_level)(prescale_texture[index], 0, &prescale_target[index]); |
| 2877 | } |
| 2878 | |
| 2879 | int bloom_index = 0; |
| 2880 | float bloom_size = (d3d->get_width() < d3d->get_height()) ? d3d->get_width() : d3d->get_height(); |
| 2881 | float bloom_width = d3d->get_width(); |
| 2882 | float bloom_height = d3d->get_height(); |
| 2883 | for (; bloom_size >= 2.0f && bloom_index < 11; bloom_size *= 0.5f) |
| 2884 | { |
| 2885 | bloom_width *= 0.5f; |
| 2886 | bloom_height *= 0.5f; |
| 2887 | |
| 2888 | result = (*d3dintf->device.create_texture)(d3d->get_device(), (int)bloom_width, (int)bloom_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bloom_texture[bloom_index]); |
| 2889 | if (result != D3D_OK) |
| 2890 | { |
| 2891 | return false; |
| 2892 | } |
| 2893 | (*d3dintf->texture.get_surface_level)(bloom_texture[bloom_index], 0, &bloom_target[bloom_index]); |
| 2894 | |
| 2895 | bloom_index++; |
| 2896 | } |
| 2897 | |
| 2898 | this->width = width; |
| 2899 | this->height = height; |
| 2900 | |
| 2901 | target_width = width * prescale_x; |
| 2902 | target_height = height * prescale_y; |
| 2903 | |
| 2904 | return true; |
| 2905 | } |
| 2906 | |
| 2907 | } |
trunk/src/osd/windows/winmain.c
| r250287 | r250288 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Aaron Giles |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // winmain.c - Win32 main program |
| 6 | | // |
| 7 | | //============================================================ |
| 8 | | |
| 9 | | // standard windows headers |
| 10 | | #define WIN32_LEAN_AND_MEAN |
| 11 | | #include <windows.h> |
| 12 | | #include <commctrl.h> |
| 13 | | #include <mmsystem.h> |
| 14 | | #include <tchar.h> |
| 15 | | #include <io.h> |
| 16 | | |
| 17 | | // standard C headers |
| 18 | | #include <ctype.h> |
| 19 | | #include <stdarg.h> |
| 20 | | #include <psapi.h> |
| 21 | | #include <dbghelp.h> |
| 22 | | |
| 23 | | // MAME headers |
| 24 | | #include "emu.h" |
| 25 | | #include "clifront.h" |
| 26 | | #include "emuopts.h" |
| 27 | | |
| 28 | | // MAMEOS headers |
| 29 | | #include "winmain.h" |
| 30 | | #include "window.h" |
| 31 | | #include "video.h" |
| 32 | | #include "input.h" |
| 33 | | #include "output.h" |
| 34 | | #include "config.h" |
| 35 | | #include "osdepend.h" |
| 36 | | #include "strconv.h" |
| 37 | | #include "winutf8.h" |
| 38 | | #include "winutil.h" |
| 39 | | #include "debugger.h" |
| 40 | | #include "winfile.h" |
| 41 | | |
| 42 | | #define DEBUG_SLOW_LOCKS 0 |
| 43 | | |
| 44 | | //************************************************************************** |
| 45 | | // MACROS |
| 46 | | //************************************************************************** |
| 47 | | |
| 48 | | #ifdef UNICODE |
| 49 | | #define UNICODE_POSTFIX "W" |
| 50 | | #else |
| 51 | | #define UNICODE_POSTFIX "A" |
| 52 | | #endif |
| 53 | | |
| 54 | | |
| 55 | | |
| 56 | | //************************************************************************** |
| 57 | | // TYPE DEFINITIONS |
| 58 | | //************************************************************************** |
| 59 | | |
| 60 | | template<typename _FunctionPtr> |
| 61 | | class dynamic_bind |
| 62 | | { |
| 63 | | public: |
| 64 | | // constructor which looks up the function |
| 65 | | dynamic_bind(const TCHAR *dll, const char *symbol) |
| 66 | | : m_function(NULL) |
| 67 | | { |
| 68 | | HMODULE module = LoadLibrary(dll); |
| 69 | | if (module != NULL) |
| 70 | | m_function = reinterpret_cast<_FunctionPtr>(GetProcAddress(module, symbol)); |
| 71 | | } |
| 72 | | |
| 73 | | // bool to test if the function is NULL or not |
| 74 | | operator bool() const { return (m_function != NULL); } |
| 75 | | |
| 76 | | // dereference to get the underlying pointer |
| 77 | | _FunctionPtr operator *() const { return m_function; } |
| 78 | | |
| 79 | | private: |
| 80 | | _FunctionPtr m_function; |
| 81 | | }; |
| 82 | | |
| 83 | | |
| 84 | | class stack_walker |
| 85 | | { |
| 86 | | public: |
| 87 | | stack_walker(); |
| 88 | | |
| 89 | | FPTR ip() const { return m_stackframe.AddrPC.Offset; } |
| 90 | | FPTR sp() const { return m_stackframe.AddrStack.Offset; } |
| 91 | | FPTR frame() const { return m_stackframe.AddrFrame.Offset; } |
| 92 | | |
| 93 | | bool reset(); |
| 94 | | void reset(CONTEXT &context, HANDLE thread); |
| 95 | | bool unwind(); |
| 96 | | |
| 97 | | private: |
| 98 | | HANDLE m_process; |
| 99 | | HANDLE m_thread; |
| 100 | | STACKFRAME64 m_stackframe; |
| 101 | | CONTEXT m_context; |
| 102 | | bool m_first; |
| 103 | | |
| 104 | | dynamic_bind<BOOL (WINAPI *)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64)> |
| 105 | | m_stack_walk_64; |
| 106 | | dynamic_bind<BOOL (WINAPI *)(HANDLE, LPCTSTR, BOOL)> m_sym_initialize; |
| 107 | | dynamic_bind<PVOID (WINAPI *)(HANDLE, DWORD64)> m_sym_function_table_access_64; |
| 108 | | dynamic_bind<DWORD64 (WINAPI *)(HANDLE, DWORD64)> m_sym_get_module_base_64; |
| 109 | | dynamic_bind<VOID (WINAPI *)(PCONTEXT)> m_rtl_capture_context; |
| 110 | | |
| 111 | | static bool s_initialized; |
| 112 | | }; |
| 113 | | |
| 114 | | |
| 115 | | class symbol_manager |
| 116 | | { |
| 117 | | public: |
| 118 | | // construction/destruction |
| 119 | | symbol_manager(const char *argv0); |
| 120 | | ~symbol_manager(); |
| 121 | | |
| 122 | | // getters |
| 123 | | FPTR last_base() const { return m_last_base; } |
| 124 | | |
| 125 | | // core symbol lookup |
| 126 | | const char *symbol_for_address(FPTR address); |
| 127 | | const char *symbol_for_address(PVOID address) { return symbol_for_address(reinterpret_cast<FPTR>(address)); } |
| 128 | | |
| 129 | | // force symbols to be cached |
| 130 | | void cache_symbols() { scan_file_for_address(0, true); } |
| 131 | | |
| 132 | | void reset_cache() { m_cache.reset(); } |
| 133 | | private: |
| 134 | | // internal helpers |
| 135 | | bool query_system_for_address(FPTR address); |
| 136 | | void scan_file_for_address(FPTR address, bool create_cache); |
| 137 | | bool parse_sym_line(const char *line, FPTR &address, std::string &symbol); |
| 138 | | bool parse_map_line(const char *line, FPTR &address, std::string &symbol); |
| 139 | | void scan_cache_for_address(FPTR address); |
| 140 | | void format_symbol(const char *name, UINT32 displacement, const char *filename = NULL, int linenumber = 0); |
| 141 | | |
| 142 | | static FPTR get_text_section_base(); |
| 143 | | |
| 144 | | struct cache_entry |
| 145 | | { |
| 146 | | cache_entry(FPTR address, const char *symbol) : |
| 147 | | m_next(NULL), m_address(address), m_name(symbol) { } |
| 148 | | cache_entry *next() const { return m_next; } |
| 149 | | |
| 150 | | cache_entry * m_next; |
| 151 | | FPTR m_address; |
| 152 | | std::string m_name; |
| 153 | | }; |
| 154 | | simple_list<cache_entry> m_cache; |
| 155 | | |
| 156 | | std::string m_mapfile; |
| 157 | | std::string m_symfile; |
| 158 | | std::string m_buffer; |
| 159 | | HANDLE m_process; |
| 160 | | FPTR m_last_base; |
| 161 | | FPTR m_text_base; |
| 162 | | |
| 163 | | dynamic_bind<BOOL (WINAPI *)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO)> m_sym_from_addr; |
| 164 | | dynamic_bind<BOOL (WINAPI *)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64)> m_sym_get_line_from_addr_64; |
| 165 | | }; |
| 166 | | |
| 167 | | |
| 168 | | class sampling_profiler |
| 169 | | { |
| 170 | | public: |
| 171 | | sampling_profiler(UINT32 max_seconds, UINT8 stack_depth); |
| 172 | | ~sampling_profiler(); |
| 173 | | |
| 174 | | void start(); |
| 175 | | void stop(); |
| 176 | | |
| 177 | | // void reset(); |
| 178 | | void print_results(symbol_manager &symbols); |
| 179 | | |
| 180 | | private: |
| 181 | | static DWORD WINAPI thread_entry(LPVOID lpParameter); |
| 182 | | void thread_run(); |
| 183 | | |
| 184 | | static int CLIB_DECL compare_address(const void *item1, const void *item2); |
| 185 | | static int CLIB_DECL compare_frequency(const void *item1, const void *item2); |
| 186 | | |
| 187 | | HANDLE m_target_thread; |
| 188 | | |
| 189 | | HANDLE m_thread; |
| 190 | | DWORD m_thread_id; |
| 191 | | volatile bool m_thread_exit; |
| 192 | | |
| 193 | | UINT8 m_stack_depth; |
| 194 | | UINT8 m_entry_stride; |
| 195 | | std::vector<FPTR> m_buffer; |
| 196 | | FPTR * m_buffer_ptr; |
| 197 | | FPTR * m_buffer_end; |
| 198 | | }; |
| 199 | | |
| 200 | | //============================================================ |
| 201 | | // winui_output_error |
| 202 | | //============================================================ |
| 203 | | |
| 204 | | class winui_output_error : public osd_output |
| 205 | | { |
| 206 | | public: |
| 207 | | virtual void output_callback(osd_output_channel channel, const char *msg, va_list args) |
| 208 | | { |
| 209 | | if (channel == OSD_OUTPUT_CHANNEL_ERROR) |
| 210 | | { |
| 211 | | char buffer[1024]; |
| 212 | | |
| 213 | | // if we are in fullscreen mode, go to windowed mode |
| 214 | | if ((video_config.windowed == 0) && (win_window_list != NULL)) |
| 215 | | winwindow_toggle_full_screen(); |
| 216 | | |
| 217 | | vsnprintf(buffer, ARRAY_LENGTH(buffer), msg, args); |
| 218 | | win_message_box_utf8(win_window_list ? win_window_list->m_hwnd : NULL, buffer, emulator_info::get_appname(), MB_OK); |
| 219 | | } |
| 220 | | else |
| 221 | | chain_output(channel, msg, args); |
| 222 | | } |
| 223 | | }; |
| 224 | | |
| 225 | | |
| 226 | | |
| 227 | | |
| 228 | | //************************************************************************** |
| 229 | | // GLOBAL VARIABLES |
| 230 | | //************************************************************************** |
| 231 | | |
| 232 | | // this line prevents globbing on the command line |
| 233 | | int _CRT_glob = 0; |
| 234 | | |
| 235 | | //************************************************************************** |
| 236 | | // LOCAL VARIABLES |
| 237 | | //************************************************************************** |
| 238 | | |
| 239 | | static LPTOP_LEVEL_EXCEPTION_FILTER pass_thru_filter; |
| 240 | | |
| 241 | | static HANDLE watchdog_reset_event; |
| 242 | | static HANDLE watchdog_exit_event; |
| 243 | | static HANDLE watchdog_thread; |
| 244 | | |
| 245 | | static running_machine *g_current_machine; |
| 246 | | |
| 247 | | static int timeresult = !TIMERR_NOERROR; |
| 248 | | static TIMECAPS timecaps; |
| 249 | | |
| 250 | | static sampling_profiler *profiler = NULL; |
| 251 | | static symbol_manager *symbols = NULL; |
| 252 | | |
| 253 | | bool stack_walker::s_initialized = false; |
| 254 | | |
| 255 | | |
| 256 | | //************************************************************************** |
| 257 | | // FUNCTION PROTOTYPES |
| 258 | | //************************************************************************** |
| 259 | | |
| 260 | | static BOOL WINAPI control_handler(DWORD type); |
| 261 | | static int is_double_click_start(int argc); |
| 262 | | static DWORD WINAPI watchdog_thread_entry(LPVOID lpParameter); |
| 263 | | static LONG WINAPI exception_filter(struct _EXCEPTION_POINTERS *info); |
| 264 | | |
| 265 | | |
| 266 | | |
| 267 | | //************************************************************************** |
| 268 | | // OPTIONS |
| 269 | | //************************************************************************** |
| 270 | | |
| 271 | | // struct definitions |
| 272 | | const options_entry windows_options::s_option_entries[] = |
| 273 | | { |
| 274 | | // performance options |
| 275 | | { NULL, NULL, OPTION_HEADER, "WINDOWS PERFORMANCE OPTIONS" }, |
| 276 | | { WINOPTION_PRIORITY "(-15-1)", "0", OPTION_INTEGER, "thread priority for the main game thread; range from -15 to 1" }, |
| 277 | | { WINOPTION_PROFILE, "0", OPTION_INTEGER, "enables profiling, specifying the stack depth to track" }, |
| 278 | | |
| 279 | | // video options |
| 280 | | { NULL, NULL, OPTION_HEADER, "WINDOWS VIDEO OPTIONS" }, |
| 281 | | { WINOPTION_MENU, "0", OPTION_BOOLEAN, "enables menu bar if available by UI implementation" }, |
| 282 | | |
| 283 | | // DirectDraw-specific options |
| 284 | | { NULL, NULL, OPTION_HEADER, "DIRECTDRAW-SPECIFIC OPTIONS" }, |
| 285 | | { WINOPTION_HWSTRETCH ";hws", "1", OPTION_BOOLEAN, "enables hardware stretching" }, |
| 286 | | |
| 287 | | // post-processing options |
| 288 | | { NULL, NULL, OPTION_HEADER, "DIRECT3D POST-PROCESSING OPTIONS" }, |
| 289 | | { WINOPTION_HLSL_ENABLE";hlsl", "0", OPTION_BOOLEAN, "enables HLSL post-processing (PS3.0 required)" }, |
| 290 | | { WINOPTION_HLSLPATH, "hlsl", OPTION_STRING, "path to hlsl files" }, |
| 291 | | { WINOPTION_HLSL_PRESCALE_X, "0", OPTION_INTEGER, "HLSL pre-scale override factor for X (0 for auto)" }, |
| 292 | | { WINOPTION_HLSL_PRESCALE_Y, "0", OPTION_INTEGER, "HLSL pre-scale override factor for Y (0 for auto)" }, |
| 293 | | { WINOPTION_HLSL_WRITE, NULL, OPTION_STRING, "enables HLSL AVI writing (huge disk bandwidth suggested)" }, |
| 294 | | { WINOPTION_HLSL_SNAP_WIDTH, "2048", OPTION_STRING, "HLSL upscaled-snapshot width" }, |
| 295 | | { WINOPTION_HLSL_SNAP_HEIGHT, "1536", OPTION_STRING, "HLSL upscaled-snapshot height" }, |
| 296 | | { WINOPTION_SHADOW_MASK_ALPHA";fs_shadwa(0.0-1.0)", "0.0", OPTION_FLOAT, "shadow mask alpha-blend value (1.0 is fully blended, 0.0 is no mask)" }, |
| 297 | | { WINOPTION_SHADOW_MASK_TEXTURE";fs_shadwt(0.0-1.0)", "aperture.png", OPTION_STRING, "shadow mask texture name" }, |
| 298 | | { WINOPTION_SHADOW_MASK_COUNT_X";fs_shadww", "6", OPTION_INTEGER, "shadow mask tile width, in screen dimensions" }, |
| 299 | | { WINOPTION_SHADOW_MASK_COUNT_Y";fs_shadwh", "6", OPTION_INTEGER, "shadow mask tile height, in screen dimensions" }, |
| 300 | | { WINOPTION_SHADOW_MASK_USIZE";fs_shadwu(0.0-1.0)", "0.1875", OPTION_FLOAT, "shadow mask texture width, in U/V dimensions" }, |
| 301 | | { WINOPTION_SHADOW_MASK_VSIZE";fs_shadwv(0.0-1.0)", "0.1875", OPTION_FLOAT, "shadow mask texture height, in U/V dimensions" }, |
| 302 | | { WINOPTION_SHADOW_MASK_UOFFSET";fs_shadwou(-1.0-1.0)", "0.0", OPTION_FLOAT, "shadow mask texture offset, in U direction" }, |
| 303 | | { WINOPTION_SHADOW_MASK_VOFFSET";fs_shadwov(-1.0-1.0)", "0.0", OPTION_FLOAT, "shadow mask texture offset, in V direction" }, |
| 304 | | { WINOPTION_CURVATURE";fs_curv(0.0-1.0)", "0.0", OPTION_FLOAT, "screen curvature amount" }, |
| 305 | | { WINOPTION_ROUND_CORNER";fs_rndc(0.0-1.0)", "0.0", OPTION_FLOAT, "screen round corner amount" }, |
| 306 | | { WINOPTION_SMOOTH_BORDER";fs_smob(0.0-1.0)", "0.0", OPTION_FLOAT, "screen smooth border amount" }, |
| 307 | | { WINOPTION_REFLECTION";fs_ref(0.0-1.0)", "0.0", OPTION_FLOAT, "screen reflection amount" }, |
| 308 | | { WINOPTION_VIGNETTING";fs_vig(0.0-1.0)", "0.0", OPTION_FLOAT, "image vignetting amount" }, |
| 309 | | /* Beam-related values below this line*/ |
| 310 | | { WINOPTION_SCANLINE_AMOUNT";fs_scanam(0.0-4.0)", "1.0", OPTION_FLOAT, "overall alpha scaling value for scanlines" }, |
| 311 | | { WINOPTION_SCANLINE_SCALE";fs_scansc(0.0-4.0)", "1.0", OPTION_FLOAT, "overall height scaling value for scanlines" }, |
| 312 | | { WINOPTION_SCANLINE_HEIGHT";fs_scanh(0.0-4.0)", "1.0", OPTION_FLOAT, "individual height scaling value for scanlines" }, |
| 313 | | { WINOPTION_SCANLINE_BRIGHT_SCALE";fs_scanbs(0.0-2.0)", "1.0", OPTION_FLOAT, "overall brightness scaling value for scanlines (multiplicative)" }, |
| 314 | | { WINOPTION_SCANLINE_BRIGHT_OFFSET";fs_scanbo(0.0-1.0)", "0.0", OPTION_FLOAT, "overall brightness offset value for scanlines (additive)" }, |
| 315 | | { WINOPTION_SCANLINE_OFFSET";fs_scanjt(0.0-4.0)", "0.0", OPTION_FLOAT, "overall interlace jitter scaling value for scanlines" }, |
| 316 | | { WINOPTION_DEFOCUS";fs_focus", "0.0,0.0", OPTION_STRING, "overall defocus value in screen-relative coords" }, |
| 317 | | { WINOPTION_CONVERGE_X";fs_convx", "0.3,0.0,-0.3",OPTION_STRING, "convergence in screen-relative X direction" }, |
| 318 | | { WINOPTION_CONVERGE_Y";fs_convy", "0.0,0.3,-0.3",OPTION_STRING, "convergence in screen-relative Y direction" }, |
| 319 | | { WINOPTION_RADIAL_CONVERGE_X";fs_rconvx", "0.0,0.0,0.0",OPTION_STRING, "radial convergence in screen-relative X direction" }, |
| 320 | | { WINOPTION_RADIAL_CONVERGE_Y";fs_rconvy", "0.0,0.0,0.0",OPTION_STRING, "radial convergence in screen-relative Y direction" }, |
| 321 | | /* RGB colorspace convolution below this line */ |
| 322 | | { WINOPTION_RED_RATIO";fs_redratio", "1.0,0.0,0.0",OPTION_STRING, "red output signal generated by input signal" }, |
| 323 | | { WINOPTION_GRN_RATIO";fs_grnratio", "0.0,1.0,0.0",OPTION_STRING, "green output signal generated by input signal" }, |
| 324 | | { WINOPTION_BLU_RATIO";fs_bluratio", "0.0,0.0,1.0",OPTION_STRING, "blue output signal generated by input signal" }, |
| 325 | | { WINOPTION_SATURATION";fs_sat(0.0-4.0)", "1.4", OPTION_FLOAT, "saturation scaling value" }, |
| 326 | | { WINOPTION_OFFSET";fs_offset", "0.0,0.0,0.0",OPTION_STRING, "signal offset value (additive)" }, |
| 327 | | { WINOPTION_SCALE";fs_scale", "0.95,0.95,0.95",OPTION_STRING, "signal scaling value (multiplicative)" }, |
| 328 | | { WINOPTION_POWER";fs_power", "0.8,0.8,0.8",OPTION_STRING, "signal power value (exponential)" }, |
| 329 | | { WINOPTION_FLOOR";fs_floor", "0.05,0.05,0.05",OPTION_STRING, "signal floor level" }, |
| 330 | | { WINOPTION_PHOSPHOR";fs_phosphor", "0.4,0.4,0.4",OPTION_STRING, "phosphorescence decay rate (0.0 is instant, 1.0 is forever)" }, |
| 331 | | /* NTSC simulation below this line */ |
| 332 | | { NULL, NULL, OPTION_HEADER, "NTSC POST-PROCESSING OPTIONS" }, |
| 333 | | { WINOPTION_YIQ_ENABLE";yiq", "0", OPTION_BOOLEAN, "enables YIQ-space HLSL post-processing" }, |
| 334 | | { WINOPTION_YIQ_CCVALUE";yiqcc", "3.59754545",OPTION_FLOAT, "Color Carrier frequency for NTSC signal processing" }, |
| 335 | | { WINOPTION_YIQ_AVALUE";yiqa", "0.5", OPTION_FLOAT, "A value for NTSC signal processing" }, |
| 336 | | { WINOPTION_YIQ_BVALUE";yiqb", "0.5", OPTION_FLOAT, "B value for NTSC signal processing" }, |
| 337 | | { WINOPTION_YIQ_OVALUE";yiqo", "1.570796325",OPTION_FLOAT, "Outgoing Color Carrier phase offset for NTSC signal processing" }, |
| 338 | | { WINOPTION_YIQ_PVALUE";yiqp", "1.0", OPTION_FLOAT, "Incoming Pixel Clock scaling value for NTSC signal processing" }, |
| 339 | | { WINOPTION_YIQ_NVALUE";yiqn", "1.0", OPTION_FLOAT, "Y filter notch width for NTSC signal processing" }, |
| 340 | | { WINOPTION_YIQ_YVALUE";yiqy", "6.0", OPTION_FLOAT, "Y filter cutoff frequency for NTSC signal processing" }, |
| 341 | | { WINOPTION_YIQ_IVALUE";yiqi", "1.2", OPTION_FLOAT, "I filter cutoff frequency for NTSC signal processing" }, |
| 342 | | { WINOPTION_YIQ_QVALUE";yiqq", "0.6", OPTION_FLOAT, "Q filter cutoff frequency for NTSC signal processing" }, |
| 343 | | { WINOPTION_YIQ_SCAN_TIME";yiqsc", "52.6", OPTION_FLOAT, "Horizontal scanline duration for NTSC signal processing (in usec)" }, |
| 344 | | { WINOPTION_YIQ_PHASE_COUNT";yiqp", "2", OPTION_INTEGER, "Phase Count value for NTSC signal processing" }, |
| 345 | | { WINOPTION_YIQ_SCAN_TIME";yiqsc", "52.6", OPTION_FLOAT, "Horizontal scanline duration for NTSC signal processing (in usec)" }, |
| 346 | | { WINOPTION_YIQ_PHASE_COUNT";yiqp", "2", OPTION_INTEGER, "Phase Count value for NTSC signal processing" }, |
| 347 | | /* Vector simulation below this line */ |
| 348 | | { NULL, NULL, OPTION_HEADER, "VECTOR POST-PROCESSING OPTIONS" }, |
| 349 | | { WINOPTION_VECTOR_LENGTH_SCALE";veclength", "0.8", OPTION_FLOAT, "How much length affects vector fade" }, |
| 350 | | { WINOPTION_VECTOR_LENGTH_RATIO";vecsize", "500.0", OPTION_FLOAT, "Vector fade length (4.0 - vectors fade the most at and above 4 pixels, etc.)" }, |
| 351 | | /* Bloom below this line */ |
| 352 | | { NULL, NULL, OPTION_HEADER, "BLOOM POST-PROCESSING OPTIONS" }, |
| 353 | | { WINOPTION_BLOOM_SCALE, "0.25", OPTION_FLOAT, "Intensity factor for bloom" }, |
| 354 | | { WINOPTION_BLOOM_OVERDRIVE, "0.0,0.0,0.0",OPTION_STRING, "Overdrive factor for bloom" }, |
| 355 | | { WINOPTION_BLOOM_LEVEL0_WEIGHT, "1.0", OPTION_FLOAT, "Bloom level 0 (full-size target) weight" }, |
| 356 | | { WINOPTION_BLOOM_LEVEL1_WEIGHT, "0.21", OPTION_FLOAT, "Bloom level 1 (half-size target) weight" }, |
| 357 | | { WINOPTION_BLOOM_LEVEL2_WEIGHT, "0.19", OPTION_FLOAT, "Bloom level 2 (quarter-size target) weight" }, |
| 358 | | { WINOPTION_BLOOM_LEVEL3_WEIGHT, "0.17", OPTION_FLOAT, "Bloom level 3 (.) weight" }, |
| 359 | | { WINOPTION_BLOOM_LEVEL4_WEIGHT, "0.15", OPTION_FLOAT, "Bloom level 4 (.) weight" }, |
| 360 | | { WINOPTION_BLOOM_LEVEL5_WEIGHT, "0.14", OPTION_FLOAT, "Bloom level 5 (.) weight" }, |
| 361 | | { WINOPTION_BLOOM_LEVEL6_WEIGHT, "0.13", OPTION_FLOAT, "Bloom level 6 (.) weight" }, |
| 362 | | { WINOPTION_BLOOM_LEVEL7_WEIGHT, "0.12", OPTION_FLOAT, "Bloom level 7 (.) weight" }, |
| 363 | | { WINOPTION_BLOOM_LEVEL8_WEIGHT, "0.11", OPTION_FLOAT, "Bloom level 8 (.) weight" }, |
| 364 | | { WINOPTION_BLOOM_LEVEL9_WEIGHT, "0.10", OPTION_FLOAT, "Bloom level 9 (.) weight" }, |
| 365 | | { WINOPTION_BLOOM_LEVEL10_WEIGHT, "0.09", OPTION_FLOAT, "Bloom level 10 (1x1 target) weight" }, |
| 366 | | |
| 367 | | // full screen options |
| 368 | | { NULL, NULL, OPTION_HEADER, "FULL SCREEN OPTIONS" }, |
| 369 | | { WINOPTION_TRIPLEBUFFER ";tb", "0", OPTION_BOOLEAN, "enables triple buffering" }, |
| 370 | | { WINOPTION_FULLSCREENBRIGHTNESS ";fsb(0.1-2.0)", "1.0", OPTION_FLOAT, "brightness value in full screen mode" }, |
| 371 | | { WINOPTION_FULLSCREENCONTRAST ";fsc(0.1-2.0)", "1.0", OPTION_FLOAT, "contrast value in full screen mode" }, |
| 372 | | { WINOPTION_FULLSCREENGAMMA ";fsg(0.1-3.0)", "1.0", OPTION_FLOAT, "gamma value in full screen mode" }, |
| 373 | | |
| 374 | | // input options |
| 375 | | { NULL, NULL, OPTION_HEADER, "INPUT DEVICE OPTIONS" }, |
| 376 | | { WINOPTION_GLOBAL_INPUTS ";global_inputs", "0", OPTION_BOOLEAN, "enables global inputs" }, |
| 377 | | { WINOPTION_DUAL_LIGHTGUN ";dual", "0", OPTION_BOOLEAN, "enables dual lightgun input" }, |
| 378 | | |
| 379 | | { NULL } |
| 380 | | }; |
| 381 | | |
| 382 | | //************************************************************************** |
| 383 | | // MAIN ENTRY POINT |
| 384 | | //************************************************************************** |
| 385 | | |
| 386 | | |
| 387 | | //============================================================ |
| 388 | | // utf8_main |
| 389 | | //============================================================ |
| 390 | | |
| 391 | | int main(int argc, char *argv[]) |
| 392 | | { |
| 393 | | // use small output buffers on non-TTYs (i.e. pipes) |
| 394 | | if (!isatty(fileno(stdout))) |
| 395 | | setvbuf(stdout, (char *) NULL, _IOFBF, 64); |
| 396 | | if (!isatty(fileno(stderr))) |
| 397 | | setvbuf(stderr, (char *) NULL, _IOFBF, 64); |
| 398 | | |
| 399 | | // initialize common controls |
| 400 | | InitCommonControls(); |
| 401 | | |
| 402 | | // set a handler to catch ctrl-c |
| 403 | | SetConsoleCtrlHandler(control_handler, TRUE); |
| 404 | | |
| 405 | | // allocate symbols |
| 406 | | symbol_manager local_symbols(argv[0]); |
| 407 | | symbols = &local_symbols; |
| 408 | | |
| 409 | | // set up exception handling |
| 410 | | pass_thru_filter = SetUnhandledExceptionFilter(exception_filter); |
| 411 | | SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); |
| 412 | | |
| 413 | | // enable stack crawls for asserts |
| 414 | | extern void (*s_debugger_stack_crawler)(); |
| 415 | | s_debugger_stack_crawler = winmain_dump_stack; |
| 416 | | |
| 417 | | |
| 418 | | // parse config and cmdline options |
| 419 | | DWORD result = 0; |
| 420 | | { |
| 421 | | windows_options options; |
| 422 | | windows_osd_interface osd(options); |
| 423 | | // if we're a GUI app, out errors to message boxes |
| 424 | | // Initialize this after the osd interface so that we are first in the |
| 425 | | // output order |
| 426 | | winui_output_error winerror; |
| 427 | | if (win_is_gui_application() || is_double_click_start(argc)) |
| 428 | | { |
| 429 | | // if we are a GUI app, output errors to message boxes |
| 430 | | osd_output::push(&winerror); |
| 431 | | // make sure any console window that opened on our behalf is nuked |
| 432 | | FreeConsole(); |
| 433 | | } |
| 434 | | osd.register_options(); |
| 435 | | cli_frontend frontend(options, osd); |
| 436 | | result = frontend.execute(argc, argv); |
| 437 | | osd_output::pop(&winerror); |
| 438 | | } |
| 439 | | // free symbols |
| 440 | | symbols = NULL; |
| 441 | | return result; |
| 442 | | } |
| 443 | | |
| 444 | | |
| 445 | | //============================================================ |
| 446 | | // windows_options |
| 447 | | //============================================================ |
| 448 | | |
| 449 | | windows_options::windows_options() |
| 450 | | : osd_options() |
| 451 | | { |
| 452 | | add_entries(s_option_entries); |
| 453 | | } |
| 454 | | |
| 455 | | |
| 456 | | //============================================================ |
| 457 | | // control_handler |
| 458 | | //============================================================ |
| 459 | | |
| 460 | | static BOOL WINAPI control_handler(DWORD type) |
| 461 | | { |
| 462 | | // indicate to the user that we detected something |
| 463 | | switch (type) |
| 464 | | { |
| 465 | | case CTRL_C_EVENT: fprintf(stderr, "Caught Ctrl+C"); break; |
| 466 | | case CTRL_BREAK_EVENT: fprintf(stderr, "Caught Ctrl+break"); break; |
| 467 | | case CTRL_CLOSE_EVENT: fprintf(stderr, "Caught console close"); break; |
| 468 | | case CTRL_LOGOFF_EVENT: fprintf(stderr, "Caught logoff"); break; |
| 469 | | case CTRL_SHUTDOWN_EVENT: fprintf(stderr, "Caught shutdown"); break; |
| 470 | | default: fprintf(stderr, "Caught unexpected console event"); break; |
| 471 | | } |
| 472 | | |
| 473 | | // if we don't have a machine yet, or if we are handling ctrl+c/ctrl+break, |
| 474 | | // just terminate hard, without throwing or handling any atexit stuff |
| 475 | | if (g_current_machine == NULL || type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT) |
| 476 | | { |
| 477 | | fprintf(stderr, ", exiting\n"); |
| 478 | | TerminateProcess(GetCurrentProcess(), MAMERR_FATALERROR); |
| 479 | | } |
| 480 | | |
| 481 | | // all other situations attempt to do a clean exit |
| 482 | | else |
| 483 | | { |
| 484 | | fprintf(stderr, ", exit requested\n"); |
| 485 | | g_current_machine->schedule_exit(); |
| 486 | | } |
| 487 | | |
| 488 | | // in all cases we handled it |
| 489 | | return TRUE; |
| 490 | | } |
| 491 | | |
| 492 | | |
| 493 | | |
| 494 | | |
| 495 | | //============================================================ |
| 496 | | // output_oslog |
| 497 | | //============================================================ |
| 498 | | |
| 499 | | static void output_oslog(const running_machine &machine, const char *buffer) |
| 500 | | { |
| 501 | | if (IsDebuggerPresent()) |
| 502 | | win_output_debug_string_utf8(buffer); |
| 503 | | } |
| 504 | | |
| 505 | | |
| 506 | | //============================================================ |
| 507 | | // constructor |
| 508 | | //============================================================ |
| 509 | | |
| 510 | | windows_osd_interface::windows_osd_interface(windows_options &options) |
| 511 | | : osd_common_t(options), m_options(options) |
| 512 | | { |
| 513 | | } |
| 514 | | |
| 515 | | |
| 516 | | //============================================================ |
| 517 | | // destructor |
| 518 | | //============================================================ |
| 519 | | |
| 520 | | windows_osd_interface::~windows_osd_interface() |
| 521 | | { |
| 522 | | } |
| 523 | | |
| 524 | | |
| 525 | | //============================================================ |
| 526 | | // video_register |
| 527 | | //============================================================ |
| 528 | | |
| 529 | | void windows_osd_interface::video_register() |
| 530 | | { |
| 531 | | video_options_add("gdi", NULL); |
| 532 | | video_options_add("ddraw", NULL); |
| 533 | | video_options_add("d3d", NULL); |
| 534 | | video_options_add("bgfx", NULL); |
| 535 | | //video_options_add("auto", NULL); // making d3d video default one |
| 536 | | } |
| 537 | | |
| 538 | | //============================================================ |
| 539 | | // init |
| 540 | | //============================================================ |
| 541 | | |
| 542 | | void windows_osd_interface::init(running_machine &machine) |
| 543 | | { |
| 544 | | // call our parent |
| 545 | | osd_common_t::init(machine); |
| 546 | | |
| 547 | | const char *stemp; |
| 548 | | windows_options &options = downcast<windows_options &>(machine.options()); |
| 549 | | |
| 550 | | // determine if we are benchmarking, and adjust options appropriately |
| 551 | | int bench = options.bench(); |
| 552 | | std::string error_string; |
| 553 | | if (bench > 0) |
| 554 | | { |
| 555 | | options.set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM, error_string); |
| 556 | | options.set_value(OSDOPTION_SOUND, "none", OPTION_PRIORITY_MAXIMUM, error_string); |
| 557 | | options.set_value(OSDOPTION_VIDEO, "none", OPTION_PRIORITY_MAXIMUM, error_string); |
| 558 | | options.set_value(OPTION_SECONDS_TO_RUN, bench, OPTION_PRIORITY_MAXIMUM, error_string); |
| 559 | | assert(error_string.empty()); |
| 560 | | } |
| 561 | | |
| 562 | | // determine if we are profiling, and adjust options appropriately |
| 563 | | int profile = options.profile(); |
| 564 | | if (profile > 0) |
| 565 | | { |
| 566 | | options.set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM, error_string); |
| 567 | | options.set_value(OSDOPTION_MULTITHREADING, false, OPTION_PRIORITY_MAXIMUM, error_string); |
| 568 | | options.set_value(OSDOPTION_NUMPROCESSORS, 1, OPTION_PRIORITY_MAXIMUM, error_string); |
| 569 | | assert(error_string.empty()); |
| 570 | | } |
| 571 | | |
| 572 | | // thread priority |
| 573 | | if (!(machine.debug_flags & DEBUG_FLAG_OSD_ENABLED)) |
| 574 | | SetThreadPriority(GetCurrentThread(), options.priority()); |
| 575 | | |
| 576 | | // get number of processors |
| 577 | | stemp = options.numprocessors(); |
| 578 | | |
| 579 | | osd_num_processors = 0; |
| 580 | | |
| 581 | | if (strcmp(stemp, "auto") != 0) |
| 582 | | { |
| 583 | | osd_num_processors = atoi(stemp); |
| 584 | | if (osd_num_processors < 1) |
| 585 | | { |
| 586 | | osd_printf_warning("Warning: numprocessors < 1 doesn't make much sense. Assuming auto ...\n"); |
| 587 | | osd_num_processors = 0; |
| 588 | | } |
| 589 | | } |
| 590 | | |
| 591 | | // initialize the subsystems |
| 592 | | osd_common_t::init_subsystems(); |
| 593 | | |
| 594 | | // notify listeners of screen configuration |
| 595 | | std::string tempstring; |
| 596 | | for (win_window_info *info = win_window_list; info != NULL; info = info->m_next) |
| 597 | | { |
| 598 | | strprintf(tempstring, "Orientation(%s)", info->m_monitor->devicename()); |
| 599 | | output_set_value(tempstring.c_str(), info->m_targetorient); |
| 600 | | } |
| 601 | | |
| 602 | | // hook up the debugger log |
| 603 | | if (options.oslog()) |
| 604 | | machine.add_logerror_callback(output_oslog); |
| 605 | | |
| 606 | | // crank up the multimedia timer resolution to its max |
| 607 | | // this gives the system much finer timeslices |
| 608 | | timeresult = timeGetDevCaps(&timecaps, sizeof(timecaps)); |
| 609 | | if (timeresult == TIMERR_NOERROR) |
| 610 | | timeBeginPeriod(timecaps.wPeriodMin); |
| 611 | | |
| 612 | | // if a watchdog thread is requested, create one |
| 613 | | int watchdog = options.watchdog(); |
| 614 | | if (watchdog != 0) |
| 615 | | { |
| 616 | | watchdog_reset_event = CreateEvent(NULL, FALSE, FALSE, NULL); |
| 617 | | assert_always(watchdog_reset_event != NULL, "Failed to create watchdog reset event"); |
| 618 | | watchdog_exit_event = CreateEvent(NULL, TRUE, FALSE, NULL); |
| 619 | | assert_always(watchdog_exit_event != NULL, "Failed to create watchdog exit event"); |
| 620 | | watchdog_thread = CreateThread(NULL, 0, watchdog_thread_entry, (LPVOID)(FPTR)watchdog, 0, NULL); |
| 621 | | assert_always(watchdog_thread != NULL, "Failed to create watchdog thread"); |
| 622 | | } |
| 623 | | |
| 624 | | // create and start the profiler |
| 625 | | if (profile > 0) |
| 626 | | { |
| 627 | | profiler = global_alloc(sampling_profiler(1000, profile - 1)); |
| 628 | | profiler->start(); |
| 629 | | } |
| 630 | | |
| 631 | | // initialize sockets |
| 632 | | win_init_sockets(); |
| 633 | | |
| 634 | | // note the existence of a machine |
| 635 | | g_current_machine = &machine; |
| 636 | | } |
| 637 | | |
| 638 | | |
| 639 | | //============================================================ |
| 640 | | // osd_exit |
| 641 | | //============================================================ |
| 642 | | |
| 643 | | void windows_osd_interface::osd_exit() |
| 644 | | { |
| 645 | | // no longer have a machine |
| 646 | | g_current_machine = NULL; |
| 647 | | |
| 648 | | // cleanup sockets |
| 649 | | win_cleanup_sockets(); |
| 650 | | |
| 651 | | osd_common_t::osd_exit(); |
| 652 | | |
| 653 | | // take down the watchdog thread if it exists |
| 654 | | if (watchdog_thread != NULL) |
| 655 | | { |
| 656 | | SetEvent(watchdog_exit_event); |
| 657 | | WaitForSingleObject(watchdog_thread, INFINITE); |
| 658 | | CloseHandle(watchdog_reset_event); |
| 659 | | CloseHandle(watchdog_exit_event); |
| 660 | | CloseHandle(watchdog_thread); |
| 661 | | watchdog_reset_event = NULL; |
| 662 | | watchdog_exit_event = NULL; |
| 663 | | watchdog_thread = NULL; |
| 664 | | } |
| 665 | | |
| 666 | | // stop the profiler |
| 667 | | if (profiler != NULL) |
| 668 | | { |
| 669 | | profiler->stop(); |
| 670 | | profiler->print_results(*symbols); |
| 671 | | global_free(profiler); |
| 672 | | } |
| 673 | | |
| 674 | | // restore the timer resolution |
| 675 | | if (timeresult == TIMERR_NOERROR) |
| 676 | | timeEndPeriod(timecaps.wPeriodMin); |
| 677 | | |
| 678 | | // one last pass at events |
| 679 | | winwindow_process_events(machine(), 0, 0); |
| 680 | | } |
| 681 | | |
| 682 | | //============================================================ |
| 683 | | // winmain_dump_stack |
| 684 | | //============================================================ |
| 685 | | |
| 686 | | void winmain_dump_stack() |
| 687 | | { |
| 688 | | // set up the stack walker |
| 689 | | stack_walker walker; |
| 690 | | if (!walker.reset()) |
| 691 | | return; |
| 692 | | |
| 693 | | // walk the stack |
| 694 | | while (walker.unwind()) |
| 695 | | fprintf(stderr, " %p: %p%s\n", (void *)walker.frame(), (void *)walker.ip(), (symbols == NULL) ? "" : symbols->symbol_for_address(walker.ip())); |
| 696 | | } |
| 697 | | |
| 698 | | |
| 699 | | //============================================================ |
| 700 | | // check_for_double_click_start |
| 701 | | //============================================================ |
| 702 | | |
| 703 | | static int is_double_click_start(int argc) |
| 704 | | { |
| 705 | | STARTUPINFO startup_info = { sizeof(STARTUPINFO) }; |
| 706 | | |
| 707 | | // determine our startup information |
| 708 | | GetStartupInfo(&startup_info); |
| 709 | | |
| 710 | | // try to determine if MAME was simply double-clicked |
| 711 | | return (argc <= 1 && startup_info.dwFlags && !(startup_info.dwFlags & STARTF_USESTDHANDLES)); |
| 712 | | } |
| 713 | | |
| 714 | | |
| 715 | | //============================================================ |
| 716 | | // watchdog_thread_entry |
| 717 | | //============================================================ |
| 718 | | |
| 719 | | static DWORD WINAPI watchdog_thread_entry(LPVOID lpParameter) |
| 720 | | { |
| 721 | | DWORD timeout = (int)(FPTR)lpParameter * 1000; |
| 722 | | |
| 723 | | while (TRUE) |
| 724 | | { |
| 725 | | HANDLE handle_list[2]; |
| 726 | | DWORD wait_result; |
| 727 | | |
| 728 | | // wait for either a reset or an exit, or a timeout |
| 729 | | handle_list[0] = watchdog_reset_event; |
| 730 | | handle_list[1] = watchdog_exit_event; |
| 731 | | wait_result = WaitForMultipleObjects(2, handle_list, FALSE, timeout); |
| 732 | | |
| 733 | | // on a reset, just loop around and re-wait |
| 734 | | if (wait_result == WAIT_OBJECT_0 + 0) |
| 735 | | continue; |
| 736 | | |
| 737 | | // on an exit, break out |
| 738 | | if (wait_result == WAIT_OBJECT_0 + 1) |
| 739 | | break; |
| 740 | | |
| 741 | | // on a timeout, kill the process |
| 742 | | if (wait_result == WAIT_TIMEOUT) |
| 743 | | { |
| 744 | | fprintf(stderr, "Terminating due to watchdog timeout\n"); |
| 745 | | fflush(stderr); |
| 746 | | TerminateProcess(GetCurrentProcess(), -1); |
| 747 | | } |
| 748 | | } |
| 749 | | return EXCEPTION_CONTINUE_SEARCH; |
| 750 | | } |
| 751 | | |
| 752 | | |
| 753 | | //============================================================ |
| 754 | | // winmain_watchdog_ping |
| 755 | | //============================================================ |
| 756 | | |
| 757 | | void winmain_watchdog_ping(void) |
| 758 | | { |
| 759 | | // if we have a watchdog, reset it |
| 760 | | if (watchdog_reset_event != NULL) |
| 761 | | SetEvent(watchdog_reset_event); |
| 762 | | } |
| 763 | | |
| 764 | | |
| 765 | | //============================================================ |
| 766 | | // exception_filter |
| 767 | | //============================================================ |
| 768 | | |
| 769 | | static LONG WINAPI exception_filter(struct _EXCEPTION_POINTERS *info) |
| 770 | | { |
| 771 | | static const struct |
| 772 | | { |
| 773 | | DWORD code; |
| 774 | | const char *string; |
| 775 | | } exception_table[] = |
| 776 | | { |
| 777 | | { EXCEPTION_ACCESS_VIOLATION, "ACCESS VIOLATION" }, |
| 778 | | { EXCEPTION_DATATYPE_MISALIGNMENT, "DATATYPE MISALIGNMENT" }, |
| 779 | | { EXCEPTION_BREAKPOINT, "BREAKPOINT" }, |
| 780 | | { EXCEPTION_SINGLE_STEP, "SINGLE STEP" }, |
| 781 | | { EXCEPTION_ARRAY_BOUNDS_EXCEEDED, "ARRAY BOUNDS EXCEEDED" }, |
| 782 | | { EXCEPTION_FLT_DENORMAL_OPERAND, "FLOAT DENORMAL OPERAND" }, |
| 783 | | { EXCEPTION_FLT_DIVIDE_BY_ZERO, "FLOAT DIVIDE BY ZERO" }, |
| 784 | | { EXCEPTION_FLT_INEXACT_RESULT, "FLOAT INEXACT RESULT" }, |
| 785 | | { EXCEPTION_FLT_INVALID_OPERATION, "FLOAT INVALID OPERATION" }, |
| 786 | | { EXCEPTION_FLT_OVERFLOW, "FLOAT OVERFLOW" }, |
| 787 | | { EXCEPTION_FLT_STACK_CHECK, "FLOAT STACK CHECK" }, |
| 788 | | { EXCEPTION_FLT_UNDERFLOW, "FLOAT UNDERFLOW" }, |
| 789 | | { EXCEPTION_INT_DIVIDE_BY_ZERO, "INTEGER DIVIDE BY ZERO" }, |
| 790 | | { EXCEPTION_INT_OVERFLOW, "INTEGER OVERFLOW" }, |
| 791 | | { EXCEPTION_PRIV_INSTRUCTION, "PRIVILEGED INSTRUCTION" }, |
| 792 | | { EXCEPTION_IN_PAGE_ERROR, "IN PAGE ERROR" }, |
| 793 | | { EXCEPTION_ILLEGAL_INSTRUCTION, "ILLEGAL INSTRUCTION" }, |
| 794 | | { EXCEPTION_NONCONTINUABLE_EXCEPTION,"NONCONTINUABLE EXCEPTION" }, |
| 795 | | { EXCEPTION_STACK_OVERFLOW, "STACK OVERFLOW" }, |
| 796 | | { EXCEPTION_INVALID_DISPOSITION, "INVALID DISPOSITION" }, |
| 797 | | { EXCEPTION_GUARD_PAGE, "GUARD PAGE VIOLATION" }, |
| 798 | | { EXCEPTION_INVALID_HANDLE, "INVALID HANDLE" }, |
| 799 | | { 0, "UNKNOWN EXCEPTION" } |
| 800 | | }; |
| 801 | | static int already_hit = 0; |
| 802 | | int i; |
| 803 | | |
| 804 | | // if we're hitting this recursively, just exit |
| 805 | | if (already_hit) |
| 806 | | return EXCEPTION_CONTINUE_SEARCH; |
| 807 | | already_hit = 1; |
| 808 | | |
| 809 | | // flush any debugging traces that were live |
| 810 | | debugger_flush_all_traces_on_abnormal_exit(); |
| 811 | | |
| 812 | | // find our man |
| 813 | | for (i = 0; exception_table[i].code != 0; i++) |
| 814 | | if (info->ExceptionRecord->ExceptionCode == exception_table[i].code) |
| 815 | | break; |
| 816 | | |
| 817 | | // print the exception type and address |
| 818 | | fprintf(stderr, "\n-----------------------------------------------------\n"); |
| 819 | | fprintf(stderr, "Exception at EIP=%p%s: %s\n", info->ExceptionRecord->ExceptionAddress, |
| 820 | | symbols->symbol_for_address((FPTR)info->ExceptionRecord->ExceptionAddress), exception_table[i].string); |
| 821 | | |
| 822 | | // for access violations, print more info |
| 823 | | if (info->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) |
| 824 | | fprintf(stderr, "While attempting to %s memory at %p\n", |
| 825 | | info->ExceptionRecord->ExceptionInformation[0] ? "write" : "read", |
| 826 | | (void *)info->ExceptionRecord->ExceptionInformation[1]); |
| 827 | | |
| 828 | | // print the state of the CPU |
| 829 | | fprintf(stderr, "-----------------------------------------------------\n"); |
| 830 | | #ifdef PTR64 |
| 831 | | fprintf(stderr, "RAX=%p RBX=%p RCX=%p RDX=%p\n", |
| 832 | | (void *)info->ContextRecord->Rax, |
| 833 | | (void *)info->ContextRecord->Rbx, |
| 834 | | (void *)info->ContextRecord->Rcx, |
| 835 | | (void *)info->ContextRecord->Rdx); |
| 836 | | fprintf(stderr, "RSI=%p RDI=%p RBP=%p RSP=%p\n", |
| 837 | | (void *)info->ContextRecord->Rsi, |
| 838 | | (void *)info->ContextRecord->Rdi, |
| 839 | | (void *)info->ContextRecord->Rbp, |
| 840 | | (void *)info->ContextRecord->Rsp); |
| 841 | | fprintf(stderr, " R8=%p R9=%p R10=%p R11=%p\n", |
| 842 | | (void *)info->ContextRecord->R8, |
| 843 | | (void *)info->ContextRecord->R9, |
| 844 | | (void *)info->ContextRecord->R10, |
| 845 | | (void *)info->ContextRecord->R11); |
| 846 | | fprintf(stderr, "R12=%p R13=%p R14=%p R15=%p\n", |
| 847 | | (void *)info->ContextRecord->R12, |
| 848 | | (void *)info->ContextRecord->R13, |
| 849 | | (void *)info->ContextRecord->R14, |
| 850 | | (void *)info->ContextRecord->R15); |
| 851 | | #else |
| 852 | | fprintf(stderr, "EAX=%p EBX=%p ECX=%p EDX=%p\n", |
| 853 | | (void *)info->ContextRecord->Eax, |
| 854 | | (void *)info->ContextRecord->Ebx, |
| 855 | | (void *)info->ContextRecord->Ecx, |
| 856 | | (void *)info->ContextRecord->Edx); |
| 857 | | fprintf(stderr, "ESI=%p EDI=%p EBP=%p ESP=%p\n", |
| 858 | | (void *)info->ContextRecord->Esi, |
| 859 | | (void *)info->ContextRecord->Edi, |
| 860 | | (void *)info->ContextRecord->Ebp, |
| 861 | | (void *)info->ContextRecord->Esp); |
| 862 | | #endif |
| 863 | | |
| 864 | | stack_walker walker; |
| 865 | | walker.reset(*info->ContextRecord, GetCurrentThread()); |
| 866 | | |
| 867 | | // reprint the actual exception address |
| 868 | | fprintf(stderr, "-----------------------------------------------------\n"); |
| 869 | | fprintf(stderr, "Stack crawl:\n"); |
| 870 | | |
| 871 | | // walk the stack |
| 872 | | while (walker.unwind()) |
| 873 | | fprintf(stderr, " %p: %p%s\n", (void *)walker.frame(), (void *)walker.ip(), (symbols == NULL) ? "" : symbols->symbol_for_address(walker.ip())); |
| 874 | | |
| 875 | | // flush stderr, so the data is actually written when output is being redirected |
| 876 | | fflush(stderr); |
| 877 | | |
| 878 | | // exit |
| 879 | | return EXCEPTION_CONTINUE_SEARCH; |
| 880 | | } |
| 881 | | |
| 882 | | |
| 883 | | //************************************************************************** |
| 884 | | // STACK WALKER |
| 885 | | //************************************************************************** |
| 886 | | |
| 887 | | //------------------------------------------------- |
| 888 | | // stack_walker - constructor |
| 889 | | //------------------------------------------------- |
| 890 | | |
| 891 | | stack_walker::stack_walker() |
| 892 | | : m_process(GetCurrentProcess()), |
| 893 | | m_thread(GetCurrentThread()), |
| 894 | | m_first(true), |
| 895 | | m_stack_walk_64(TEXT("dbghelp.dll"), "StackWalk64"), |
| 896 | | m_sym_initialize(TEXT("dbghelp.dll"), "SymInitialize"), |
| 897 | | m_sym_function_table_access_64(TEXT("dbghelp.dll"), "SymFunctionTableAccess64"), |
| 898 | | m_sym_get_module_base_64(TEXT("dbghelp.dll"), "SymGetModuleBase64"), |
| 899 | | m_rtl_capture_context(TEXT("kernel32.dll"), "RtlCaptureContext") |
| 900 | | { |
| 901 | | // zap the structs |
| 902 | | memset(&m_stackframe, 0, sizeof(m_stackframe)); |
| 903 | | memset(&m_context, 0, sizeof(m_context)); |
| 904 | | |
| 905 | | // initialize the symbols |
| 906 | | if (!s_initialized && m_sym_initialize && m_stack_walk_64 && m_sym_function_table_access_64 && m_sym_get_module_base_64) |
| 907 | | { |
| 908 | | (*m_sym_initialize)(m_process, NULL, TRUE); |
| 909 | | s_initialized = true; |
| 910 | | } |
| 911 | | } |
| 912 | | |
| 913 | | |
| 914 | | //------------------------------------------------- |
| 915 | | // reset - set up a new context |
| 916 | | //------------------------------------------------- |
| 917 | | |
| 918 | | bool stack_walker::reset() |
| 919 | | { |
| 920 | | // set up the initial state |
| 921 | | if (!m_rtl_capture_context) |
| 922 | | return false; |
| 923 | | (*m_rtl_capture_context)(&m_context); |
| 924 | | m_thread = GetCurrentThread(); |
| 925 | | m_first = true; |
| 926 | | |
| 927 | | // initialize the stackframe |
| 928 | | memset(&m_stackframe, 0, sizeof(m_stackframe)); |
| 929 | | m_stackframe.AddrPC.Mode = AddrModeFlat; |
| 930 | | m_stackframe.AddrFrame.Mode = AddrModeFlat; |
| 931 | | m_stackframe.AddrStack.Mode = AddrModeFlat; |
| 932 | | |
| 933 | | // pull architecture-specific fields from the context |
| 934 | | #ifdef PTR64 |
| 935 | | m_stackframe.AddrPC.Offset = m_context.Rip; |
| 936 | | m_stackframe.AddrFrame.Offset = m_context.Rsp; |
| 937 | | m_stackframe.AddrStack.Offset = m_context.Rsp; |
| 938 | | #else |
| 939 | | m_stackframe.AddrPC.Offset = m_context.Eip; |
| 940 | | m_stackframe.AddrFrame.Offset = m_context.Ebp; |
| 941 | | m_stackframe.AddrStack.Offset = m_context.Esp; |
| 942 | | #endif |
| 943 | | return true; |
| 944 | | } |
| 945 | | |
| 946 | | void stack_walker::reset(CONTEXT &initial, HANDLE thread) |
| 947 | | { |
| 948 | | // set up the initial state |
| 949 | | m_context = initial; |
| 950 | | m_thread = thread; |
| 951 | | m_first = true; |
| 952 | | |
| 953 | | // initialize the stackframe |
| 954 | | memset(&m_stackframe, 0, sizeof(m_stackframe)); |
| 955 | | m_stackframe.AddrPC.Mode = AddrModeFlat; |
| 956 | | m_stackframe.AddrFrame.Mode = AddrModeFlat; |
| 957 | | m_stackframe.AddrStack.Mode = AddrModeFlat; |
| 958 | | |
| 959 | | // pull architecture-specific fields from the context |
| 960 | | #ifdef PTR64 |
| 961 | | m_stackframe.AddrPC.Offset = m_context.Rip; |
| 962 | | m_stackframe.AddrFrame.Offset = m_context.Rsp; |
| 963 | | m_stackframe.AddrStack.Offset = m_context.Rsp; |
| 964 | | #else |
| 965 | | m_stackframe.AddrPC.Offset = m_context.Eip; |
| 966 | | m_stackframe.AddrFrame.Offset = m_context.Ebp; |
| 967 | | m_stackframe.AddrStack.Offset = m_context.Esp; |
| 968 | | #endif |
| 969 | | } |
| 970 | | |
| 971 | | |
| 972 | | //------------------------------------------------- |
| 973 | | // unwind - unwind a single level |
| 974 | | //------------------------------------------------- |
| 975 | | |
| 976 | | bool stack_walker::unwind() |
| 977 | | { |
| 978 | | // if we were able to initialize, then we have everything we need |
| 979 | | if (s_initialized) |
| 980 | | { |
| 981 | | #ifdef PTR64 |
| 982 | | return (*m_stack_walk_64)(IMAGE_FILE_MACHINE_AMD64, m_process, m_thread, &m_stackframe, &m_context, NULL, *m_sym_function_table_access_64, *m_sym_get_module_base_64, NULL); |
| 983 | | #else |
| 984 | | return (*m_stack_walk_64)(IMAGE_FILE_MACHINE_I386, m_process, m_thread, &m_stackframe, &m_context, NULL, *m_sym_function_table_access_64, *m_sym_get_module_base_64, NULL); |
| 985 | | #endif |
| 986 | | } |
| 987 | | |
| 988 | | // otherwise, fake the first unwind, which will just return info from the context |
| 989 | | else |
| 990 | | { |
| 991 | | bool result = m_first; |
| 992 | | m_first = false; |
| 993 | | return result; |
| 994 | | } |
| 995 | | } |
| 996 | | |
| 997 | | |
| 998 | | |
| 999 | | //************************************************************************** |
| 1000 | | // SYMBOL MANAGER |
| 1001 | | //************************************************************************** |
| 1002 | | |
| 1003 | | //------------------------------------------------- |
| 1004 | | // symbol_manager - constructor |
| 1005 | | //------------------------------------------------- |
| 1006 | | |
| 1007 | | symbol_manager::symbol_manager(const char *argv0) |
| 1008 | | : m_mapfile(argv0), |
| 1009 | | m_symfile(argv0), |
| 1010 | | m_process(GetCurrentProcess()), |
| 1011 | | m_last_base(0), |
| 1012 | | m_text_base(0), |
| 1013 | | m_sym_from_addr(TEXT("dbghelp.dll"), "SymFromAddr"), |
| 1014 | | m_sym_get_line_from_addr_64(TEXT("dbghelp.dll"), "SymGetLineFromAddr64") |
| 1015 | | { |
| 1016 | | #ifdef __GNUC__ |
| 1017 | | // compute the name of the mapfile |
| 1018 | | int extoffs = m_mapfile.find_last_of('.'); |
| 1019 | | if (extoffs != -1) |
| 1020 | | m_mapfile.substr(0, extoffs); |
| 1021 | | m_mapfile.append(".map"); |
| 1022 | | |
| 1023 | | // and the name of the symfile |
| 1024 | | extoffs = m_symfile.find_last_of('.'); |
| 1025 | | if (extoffs != -1) |
| 1026 | | m_symfile = m_symfile.substr(0, extoffs); |
| 1027 | | m_symfile.append(".sym"); |
| 1028 | | |
| 1029 | | // figure out the base of the .text section |
| 1030 | | m_text_base = get_text_section_base(); |
| 1031 | | #endif |
| 1032 | | |
| 1033 | | // expand the buffer to be decently large up front |
| 1034 | | strprintf(m_buffer,"%500s", ""); |
| 1035 | | } |
| 1036 | | |
| 1037 | | |
| 1038 | | //------------------------------------------------- |
| 1039 | | // ~symbol_manager - destructor |
| 1040 | | //------------------------------------------------- |
| 1041 | | |
| 1042 | | symbol_manager::~symbol_manager() |
| 1043 | | { |
| 1044 | | } |
| 1045 | | |
| 1046 | | |
| 1047 | | //------------------------------------------------- |
| 1048 | | // symbol_for_address - return a symbol by looking |
| 1049 | | // it up either in the cache or by scanning the |
| 1050 | | // file |
| 1051 | | //------------------------------------------------- |
| 1052 | | |
| 1053 | | const char *symbol_manager::symbol_for_address(FPTR address) |
| 1054 | | { |
| 1055 | | // default the buffer |
| 1056 | | m_buffer.assign(" (not found)"); |
| 1057 | | m_last_base = 0; |
| 1058 | | |
| 1059 | | // first try to do it using system APIs |
| 1060 | | if (!query_system_for_address(address)) |
| 1061 | | { |
| 1062 | | // if that fails, scan the cache if we have one |
| 1063 | | if (m_cache.first() != NULL) |
| 1064 | | scan_cache_for_address(address); |
| 1065 | | |
| 1066 | | // or else try to open a sym/map file and find it there |
| 1067 | | else |
| 1068 | | scan_file_for_address(address, false); |
| 1069 | | } |
| 1070 | | return m_buffer.c_str(); |
| 1071 | | } |
| 1072 | | |
| 1073 | | |
| 1074 | | //------------------------------------------------- |
| 1075 | | // query_system_for_address - ask the system to |
| 1076 | | // look up our address |
| 1077 | | //------------------------------------------------- |
| 1078 | | |
| 1079 | | bool symbol_manager::query_system_for_address(FPTR address) |
| 1080 | | { |
| 1081 | | // need at least the sym_from_addr API |
| 1082 | | if (!m_sym_from_addr) |
| 1083 | | return false; |
| 1084 | | |
| 1085 | | BYTE info_buffer[sizeof(SYMBOL_INFO) + 256] = { 0 }; |
| 1086 | | SYMBOL_INFO &info = *reinterpret_cast<SYMBOL_INFO *>(&info_buffer[0]); |
| 1087 | | DWORD64 displacement; |
| 1088 | | |
| 1089 | | // even through the struct says TCHAR, we actually get back an ANSI string here |
| 1090 | | info.SizeOfStruct = sizeof(info); |
| 1091 | | info.MaxNameLen = sizeof(info_buffer) - sizeof(info); |
| 1092 | | if ((*m_sym_from_addr)(m_process, address, &displacement, &info)) |
| 1093 | | { |
| 1094 | | // try to get source info as well; again we are returned an ANSI string |
| 1095 | | IMAGEHLP_LINE64 lineinfo = { sizeof(lineinfo) }; |
| 1096 | | DWORD linedisp; |
| 1097 | | if (m_sym_get_line_from_addr_64 && (*m_sym_get_line_from_addr_64)(m_process, address, &linedisp, &lineinfo)) |
| 1098 | | format_symbol(info.Name, displacement, lineinfo.FileName, lineinfo.LineNumber); |
| 1099 | | else |
| 1100 | | format_symbol(info.Name, displacement); |
| 1101 | | |
| 1102 | | // set the last base |
| 1103 | | m_last_base = address - displacement; |
| 1104 | | return true; |
| 1105 | | } |
| 1106 | | return false; |
| 1107 | | } |
| 1108 | | |
| 1109 | | |
| 1110 | | //------------------------------------------------- |
| 1111 | | // scan_file_for_address - walk either the map |
| 1112 | | // or symbol files and find the best match for |
| 1113 | | // the given address, optionally creating a cache |
| 1114 | | // along the way |
| 1115 | | //------------------------------------------------- |
| 1116 | | |
| 1117 | | void symbol_manager::scan_file_for_address(FPTR address, bool create_cache) |
| 1118 | | { |
| 1119 | | bool is_symfile = false; |
| 1120 | | FILE *srcfile = NULL; |
| 1121 | | |
| 1122 | | #ifdef __GNUC__ |
| 1123 | | // see if we have a symbol file (gcc only) |
| 1124 | | srcfile = fopen(m_symfile.c_str(), "r"); |
| 1125 | | is_symfile = (srcfile != NULL); |
| 1126 | | #endif |
| 1127 | | |
| 1128 | | // if not, see if we have a map file |
| 1129 | | if (srcfile == NULL) |
| 1130 | | srcfile = fopen(m_mapfile.c_str(), "r"); |
| 1131 | | |
| 1132 | | // if not, fail |
| 1133 | | if (srcfile == NULL) |
| 1134 | | return; |
| 1135 | | |
| 1136 | | // reset the best info |
| 1137 | | std::string best_symbol; |
| 1138 | | FPTR best_addr = 0; |
| 1139 | | |
| 1140 | | // parse the file, looking for valid entries |
| 1141 | | std::string symbol; |
| 1142 | | char line[1024]; |
| 1143 | | while (fgets(line, sizeof(line) - 1, srcfile)) |
| 1144 | | { |
| 1145 | | // parse the line looking for an interesting symbol |
| 1146 | | FPTR addr = 0; |
| 1147 | | bool valid = is_symfile ? parse_sym_line(line, addr, symbol) : parse_map_line(line, addr, symbol); |
| 1148 | | |
| 1149 | | // if we got one, see if this is the best |
| 1150 | | if (valid) |
| 1151 | | { |
| 1152 | | // if this is the best one so far, remember it |
| 1153 | | if (addr <= address && addr > best_addr) |
| 1154 | | { |
| 1155 | | best_addr = addr; |
| 1156 | | best_symbol = symbol; |
| 1157 | | } |
| 1158 | | |
| 1159 | | // also create a cache entry if we can |
| 1160 | | if (create_cache) |
| 1161 | | m_cache.append(*global_alloc(cache_entry(addr, symbol.c_str()))); |
| 1162 | | } |
| 1163 | | } |
| 1164 | | |
| 1165 | | // close the file |
| 1166 | | fclose(srcfile); |
| 1167 | | |
| 1168 | | // format the symbol and remember the last base |
| 1169 | | format_symbol(best_symbol.c_str(), address - best_addr); |
| 1170 | | m_last_base = best_addr; |
| 1171 | | } |
| 1172 | | |
| 1173 | | |
| 1174 | | //------------------------------------------------- |
| 1175 | | // scan_cache_for_address - walk the cache to |
| 1176 | | // find the best match for the given address |
| 1177 | | //------------------------------------------------- |
| 1178 | | |
| 1179 | | void symbol_manager::scan_cache_for_address(FPTR address) |
| 1180 | | { |
| 1181 | | // reset the best info |
| 1182 | | std::string best_symbol; |
| 1183 | | FPTR best_addr = 0; |
| 1184 | | |
| 1185 | | // walk the cache, looking for valid entries |
| 1186 | | for (cache_entry *entry = m_cache.first(); entry != NULL; entry = entry->next()) |
| 1187 | | |
| 1188 | | // if this is the best one so far, remember it |
| 1189 | | if (entry->m_address <= address && entry->m_address > best_addr) |
| 1190 | | { |
| 1191 | | best_addr = entry->m_address; |
| 1192 | | best_symbol = entry->m_name; |
| 1193 | | } |
| 1194 | | |
| 1195 | | // format the symbol and remember the last base |
| 1196 | | format_symbol(best_symbol.c_str(), address - best_addr); |
| 1197 | | m_last_base = best_addr; |
| 1198 | | } |
| 1199 | | |
| 1200 | | |
| 1201 | | //------------------------------------------------- |
| 1202 | | // parse_sym_line - parse a line from a sym file |
| 1203 | | // which is just the output of objdump |
| 1204 | | //------------------------------------------------- |
| 1205 | | |
| 1206 | | bool symbol_manager::parse_sym_line(const char *line, FPTR &address, std::string &symbol) |
| 1207 | | { |
| 1208 | | #ifdef __GNUC__ |
| 1209 | | /* |
| 1210 | | 32-bit gcc symbol line: |
| 1211 | | [271778](sec 1)(fl 0x00)(ty 20)(scl 3) (nx 0) 0x007df675 line_to_symbol(char const*, unsigned int&, bool) |
| 1212 | | |
| 1213 | | 64-bit gcc symbol line: |
| 1214 | | [271775](sec 1)(fl 0x00)(ty 20)(scl 3) (nx 0) 0x00000000008dd1e9 line_to_symbol(char const*, unsigned long long&, bool) |
| 1215 | | */ |
| 1216 | | |
| 1217 | | // first look for a (ty) entry |
| 1218 | | const char *type = strstr(line, "(ty 20)"); |
| 1219 | | if (type == NULL) |
| 1220 | | return false; |
| 1221 | | |
| 1222 | | // scan forward in the line to find the address |
| 1223 | | bool in_parens = false; |
| 1224 | | for (const char *chptr = type; *chptr != 0; chptr++) |
| 1225 | | { |
| 1226 | | // track open/close parentheses |
| 1227 | | if (*chptr == '(') |
| 1228 | | in_parens = true; |
| 1229 | | else if (*chptr == ')') |
| 1230 | | in_parens = false; |
| 1231 | | |
| 1232 | | // otherwise, look for an 0x address |
| 1233 | | else if (!in_parens && *chptr == '0' && chptr[1] == 'x') |
| 1234 | | { |
| 1235 | | // make sure we can get an address |
| 1236 | | void *temp; |
| 1237 | | if (sscanf(chptr, "0x%p", &temp) != 1) |
| 1238 | | return false; |
| 1239 | | address = m_text_base + reinterpret_cast<FPTR>(temp); |
| 1240 | | |
| 1241 | | // skip forward until we're past the space |
| 1242 | | while (*chptr != 0 && !isspace(*chptr)) |
| 1243 | | chptr++; |
| 1244 | | |
| 1245 | | // extract the symbol name |
| 1246 | | strtrimspace(symbol.assign(chptr)); |
| 1247 | | return (symbol.length() > 0); |
| 1248 | | } |
| 1249 | | } |
| 1250 | | #endif |
| 1251 | | return false; |
| 1252 | | } |
| 1253 | | |
| 1254 | | |
| 1255 | | //------------------------------------------------- |
| 1256 | | // parse_map_line - parse a line from a linker- |
| 1257 | | // generated map file |
| 1258 | | //------------------------------------------------- |
| 1259 | | |
| 1260 | | bool symbol_manager::parse_map_line(const char *line, FPTR &address, std::string &symbol) |
| 1261 | | { |
| 1262 | | #ifdef __GNUC__ |
| 1263 | | /* |
| 1264 | | 32-bit gcc map line: |
| 1265 | | 0x0089cb00 nbmj9195_palette_r(_address_space const*, unsigned int) |
| 1266 | | |
| 1267 | | 64-bit gcc map line: |
| 1268 | | 0x0000000000961afc nbmj9195_palette_r(_address_space const*, unsigned int) |
| 1269 | | */ |
| 1270 | | |
| 1271 | | // find a matching start |
| 1272 | | if (strncmp(line, " 0x", 18) == 0) |
| 1273 | | { |
| 1274 | | // make sure we can get an address |
| 1275 | | void *temp; |
| 1276 | | if (sscanf(&line[16], "0x%p", &temp) != 1) |
| 1277 | | return false; |
| 1278 | | address = reinterpret_cast<FPTR>(temp); |
| 1279 | | |
| 1280 | | // skip forward until we're past the space |
| 1281 | | const char *chptr = &line[16]; |
| 1282 | | while (*chptr != 0 && !isspace(*chptr)) |
| 1283 | | chptr++; |
| 1284 | | |
| 1285 | | // extract the symbol name |
| 1286 | | strtrimspace(symbol.assign(chptr)); |
| 1287 | | return (symbol.length() > 0); |
| 1288 | | } |
| 1289 | | #endif |
| 1290 | | return false; |
| 1291 | | } |
| 1292 | | |
| 1293 | | |
| 1294 | | //------------------------------------------------- |
| 1295 | | // format_symbol - common symbol formatting |
| 1296 | | //------------------------------------------------- |
| 1297 | | |
| 1298 | | void symbol_manager::format_symbol(const char *name, UINT32 displacement, const char *filename, int linenumber) |
| 1299 | | { |
| 1300 | | // start with the address and offset |
| 1301 | | strprintf(m_buffer, " (%s", name); |
| 1302 | | if (displacement != 0) |
| 1303 | | strcatprintf(m_buffer, "+0x%04x", (UINT32)displacement); |
| 1304 | | |
| 1305 | | // append file/line if present |
| 1306 | | if (filename != NULL) |
| 1307 | | strcatprintf(m_buffer, ", %s:%d", filename, linenumber); |
| 1308 | | |
| 1309 | | // close up the string |
| 1310 | | m_buffer.append(")"); |
| 1311 | | } |
| 1312 | | |
| 1313 | | |
| 1314 | | //------------------------------------------------- |
| 1315 | | // get_text_section_base - figure out the base |
| 1316 | | // of the .text section |
| 1317 | | //------------------------------------------------- |
| 1318 | | |
| 1319 | | FPTR symbol_manager::get_text_section_base() |
| 1320 | | { |
| 1321 | | dynamic_bind<PIMAGE_SECTION_HEADER (WINAPI *)(PIMAGE_NT_HEADERS, PVOID, ULONG)> image_rva_to_section(TEXT("dbghelp.dll"), "ImageRvaToSection"); |
| 1322 | | dynamic_bind<PIMAGE_NT_HEADERS (WINAPI *)(PVOID)> image_nt_header(TEXT("dbghelp.dll"), "ImageNtHeader"); |
| 1323 | | |
| 1324 | | // start with the image base |
| 1325 | | PVOID base = reinterpret_cast<PVOID>(GetModuleHandleUni()); |
| 1326 | | assert(base != NULL); |
| 1327 | | |
| 1328 | | // make sure we have the functions we need |
| 1329 | | if (image_nt_header && image_rva_to_section) |
| 1330 | | { |
| 1331 | | // get the NT header |
| 1332 | | PIMAGE_NT_HEADERS headers = (*image_nt_header)(base); |
| 1333 | | assert(headers != NULL); |
| 1334 | | |
| 1335 | | // look ourself up (assuming we are in the .text section) |
| 1336 | | PIMAGE_SECTION_HEADER section = (*image_rva_to_section)(headers, base, reinterpret_cast<FPTR>(get_text_section_base) - reinterpret_cast<FPTR>(base)); |
| 1337 | | if (section != NULL) |
| 1338 | | return reinterpret_cast<FPTR>(base) + section->VirtualAddress; |
| 1339 | | } |
| 1340 | | |
| 1341 | | // fallback to returning the image base (wrong) |
| 1342 | | return reinterpret_cast<FPTR>(base); |
| 1343 | | } |
| 1344 | | |
| 1345 | | |
| 1346 | | |
| 1347 | | //************************************************************************** |
| 1348 | | // SAMPLING PROFILER |
| 1349 | | //************************************************************************** |
| 1350 | | |
| 1351 | | //------------------------------------------------- |
| 1352 | | // sampling_profiler - constructor |
| 1353 | | //------------------------------------------------- |
| 1354 | | |
| 1355 | | sampling_profiler::sampling_profiler(UINT32 max_seconds, UINT8 stack_depth = 0) |
| 1356 | | : m_thread(NULL), |
| 1357 | | m_thread_id(0), |
| 1358 | | m_thread_exit(false), |
| 1359 | | m_stack_depth(stack_depth), |
| 1360 | | m_entry_stride(stack_depth + 2), |
| 1361 | | m_buffer(max_seconds * 1000 * m_entry_stride), |
| 1362 | | m_buffer_ptr(&m_buffer[0]), |
| 1363 | | m_buffer_end(&m_buffer[0] + max_seconds * 1000 * m_entry_stride) |
| 1364 | | { |
| 1365 | | } |
| 1366 | | |
| 1367 | | |
| 1368 | | //------------------------------------------------- |
| 1369 | | // sampling_profiler - destructor |
| 1370 | | //------------------------------------------------- |
| 1371 | | |
| 1372 | | sampling_profiler::~sampling_profiler() |
| 1373 | | { |
| 1374 | | } |
| 1375 | | |
| 1376 | | |
| 1377 | | //------------------------------------------------- |
| 1378 | | // start - begin gathering profiling information |
| 1379 | | //------------------------------------------------- |
| 1380 | | |
| 1381 | | void sampling_profiler::start() |
| 1382 | | { |
| 1383 | | // do the dance to get a handle to ourself |
| 1384 | | BOOL result = DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &m_target_thread, |
| 1385 | | THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION, FALSE, 0); |
| 1386 | | assert_always(result, "Failed to get thread handle for main thread"); |
| 1387 | | |
| 1388 | | // reset the exit flag |
| 1389 | | m_thread_exit = false; |
| 1390 | | |
| 1391 | | // start the thread |
| 1392 | | m_thread = CreateThread(NULL, 0, thread_entry, (LPVOID)this, 0, &m_thread_id); |
| 1393 | | assert_always(m_thread != NULL, "Failed to create profiler thread\n"); |
| 1394 | | |
| 1395 | | // max out the priority |
| 1396 | | SetThreadPriority(m_thread, THREAD_PRIORITY_TIME_CRITICAL); |
| 1397 | | } |
| 1398 | | |
| 1399 | | |
| 1400 | | //------------------------------------------------- |
| 1401 | | // stop - stop gathering profiling information |
| 1402 | | //------------------------------------------------- |
| 1403 | | |
| 1404 | | void sampling_profiler::stop() |
| 1405 | | { |
| 1406 | | // set the flag and wait a couple of seconds (max) |
| 1407 | | m_thread_exit = true; |
| 1408 | | WaitForSingleObject(m_thread, 2000); |
| 1409 | | |
| 1410 | | // regardless, close the handle |
| 1411 | | CloseHandle(m_thread); |
| 1412 | | } |
| 1413 | | |
| 1414 | | |
| 1415 | | //------------------------------------------------- |
| 1416 | | // compare_address - compare two entries by their |
| 1417 | | // bucket address |
| 1418 | | //------------------------------------------------- |
| 1419 | | |
| 1420 | | int CLIB_DECL sampling_profiler::compare_address(const void *item1, const void *item2) |
| 1421 | | { |
| 1422 | | const FPTR *entry1 = reinterpret_cast<const FPTR *>(item1); |
| 1423 | | const FPTR *entry2 = reinterpret_cast<const FPTR *>(item2); |
| 1424 | | int mincount = MIN(entry1[0], entry2[0]); |
| 1425 | | |
| 1426 | | // sort in order of: bucket, caller, caller's caller, etc. |
| 1427 | | for (int index = 1; index <= mincount; index++) |
| 1428 | | if (entry1[index] != entry2[index]) |
| 1429 | | return entry1[index] - entry2[index]; |
| 1430 | | |
| 1431 | | // if we match to the end, sort by the depth of the stack |
| 1432 | | return entry1[0] - entry2[0]; |
| 1433 | | } |
| 1434 | | |
| 1435 | | |
| 1436 | | //------------------------------------------------- |
| 1437 | | // compare_frequency - compare two entries by |
| 1438 | | // their frequency of occurrence |
| 1439 | | //------------------------------------------------- |
| 1440 | | |
| 1441 | | int CLIB_DECL sampling_profiler::compare_frequency(const void *item1, const void *item2) |
| 1442 | | { |
| 1443 | | const FPTR *entry1 = reinterpret_cast<const FPTR *>(item1); |
| 1444 | | const FPTR *entry2 = reinterpret_cast<const FPTR *>(item2); |
| 1445 | | |
| 1446 | | // sort by frequency, then by address |
| 1447 | | if (entry1[0] != entry2[0]) |
| 1448 | | return entry2[0] - entry1[0]; |
| 1449 | | return entry1[1] - entry2[1]; |
| 1450 | | } |
| 1451 | | |
| 1452 | | |
| 1453 | | //------------------------------------------------- |
| 1454 | | // print_results - output the results |
| 1455 | | //------------------------------------------------- |
| 1456 | | |
| 1457 | | void sampling_profiler::print_results(symbol_manager &symbols) |
| 1458 | | { |
| 1459 | | // cache the symbols |
| 1460 | | symbols.cache_symbols(); |
| 1461 | | |
| 1462 | | // step 1: find the base of each entry |
| 1463 | | for (FPTR *current = &m_buffer[0]; current < m_buffer_ptr; current += m_entry_stride) |
| 1464 | | { |
| 1465 | | assert(current[0] >= 1 && current[0] < m_entry_stride); |
| 1466 | | |
| 1467 | | // convert the sampled PC to its function base as a bucket |
| 1468 | | symbols.symbol_for_address(current[1]); |
| 1469 | | current[1] = symbols.last_base(); |
| 1470 | | } |
| 1471 | | |
| 1472 | | // step 2: sort the results |
| 1473 | | qsort(&m_buffer[0], (m_buffer_ptr - &m_buffer[0]) / m_entry_stride, m_entry_stride * sizeof(FPTR), compare_address); |
| 1474 | | |
| 1475 | | // step 3: count and collapse unique entries |
| 1476 | | UINT32 total_count = 0; |
| 1477 | | for (FPTR *current = &m_buffer[0]; current < m_buffer_ptr; ) |
| 1478 | | { |
| 1479 | | int count = 1; |
| 1480 | | FPTR *scan; |
| 1481 | | for (scan = current + m_entry_stride; scan < m_buffer_ptr; scan += m_entry_stride) |
| 1482 | | { |
| 1483 | | if (compare_address(current, scan) != 0) |
| 1484 | | break; |
| 1485 | | scan[0] = 0; |
| 1486 | | count++; |
| 1487 | | } |
| 1488 | | current[0] = count; |
| 1489 | | total_count += count; |
| 1490 | | current = scan; |
| 1491 | | } |
| 1492 | | |
| 1493 | | // step 4: sort the results again, this time by frequency |
| 1494 | | qsort(&m_buffer[0], (m_buffer_ptr - &m_buffer[0]) / m_entry_stride, m_entry_stride * sizeof(FPTR), compare_frequency); |
| 1495 | | |
| 1496 | | // step 5: print the results |
| 1497 | | UINT32 num_printed = 0; |
| 1498 | | for (FPTR *current = &m_buffer[0]; current < m_buffer_ptr && num_printed < 30; current += m_entry_stride) |
| 1499 | | { |
| 1500 | | // once we hit 0 frequency, we're done |
| 1501 | | if (current[0] == 0) |
| 1502 | | break; |
| 1503 | | |
| 1504 | | // output the result |
| 1505 | | printf("%4.1f%% - %6d : %p%s\n", (double)current[0] * 100.0 / (double)total_count, (UINT32)current[0], reinterpret_cast<void *>(current[1]), symbols.symbol_for_address(current[1])); |
| 1506 | | for (int index = 2; index < m_entry_stride; index++) |
| 1507 | | { |
| 1508 | | if (current[index] == 0) |
| 1509 | | break; |
| 1510 | | printf(" %p%s\n", reinterpret_cast<void *>(current[index]), symbols.symbol_for_address(current[index])); |
| 1511 | | } |
| 1512 | | printf("\n"); |
| 1513 | | num_printed++; |
| 1514 | | } |
| 1515 | | symbols.reset_cache(); |
| 1516 | | } |
| 1517 | | |
| 1518 | | |
| 1519 | | //------------------------------------------------- |
| 1520 | | // thread_entry - thread entry stub |
| 1521 | | //------------------------------------------------- |
| 1522 | | |
| 1523 | | DWORD WINAPI sampling_profiler::thread_entry(LPVOID lpParameter) |
| 1524 | | { |
| 1525 | | reinterpret_cast<sampling_profiler *>(lpParameter)->thread_run(); |
| 1526 | | return 0; |
| 1527 | | } |
| 1528 | | |
| 1529 | | |
| 1530 | | //------------------------------------------------- |
| 1531 | | // thread_run - sampling thread |
| 1532 | | //------------------------------------------------- |
| 1533 | | |
| 1534 | | void sampling_profiler::thread_run() |
| 1535 | | { |
| 1536 | | CONTEXT context; |
| 1537 | | memset(&context, 0, sizeof(context)); |
| 1538 | | |
| 1539 | | // loop until done |
| 1540 | | stack_walker walker; |
| 1541 | | while (!m_thread_exit && m_buffer_ptr < m_buffer_end) |
| 1542 | | { |
| 1543 | | // pause the main thread and get its context |
| 1544 | | SuspendThread(m_target_thread); |
| 1545 | | context.ContextFlags = CONTEXT_FULL; |
| 1546 | | GetThreadContext(m_target_thread, &context); |
| 1547 | | |
| 1548 | | // first entry is a count |
| 1549 | | FPTR *count = m_buffer_ptr++; |
| 1550 | | *count = 0; |
| 1551 | | |
| 1552 | | // iterate over the frames until we run out or hit an error |
| 1553 | | walker.reset(context, m_target_thread); |
| 1554 | | int frame; |
| 1555 | | for (frame = 0; frame <= m_stack_depth && walker.unwind(); frame++) |
| 1556 | | { |
| 1557 | | *m_buffer_ptr++ = walker.ip(); |
| 1558 | | *count += 1; |
| 1559 | | } |
| 1560 | | |
| 1561 | | // fill in any missing parts with NULLs |
| 1562 | | for (; frame <= m_stack_depth; frame++) |
| 1563 | | *m_buffer_ptr++ = 0; |
| 1564 | | |
| 1565 | | // resume the thread |
| 1566 | | ResumeThread(m_target_thread); |
| 1567 | | |
| 1568 | | // sleep for 1ms |
| 1569 | | Sleep(1); |
| 1570 | | } |
| 1571 | | } |
trunk/src/osd/windows/winmain.cpp
| r0 | r250288 | |
| 1 | // license:BSD-3-Clause |
| 2 | // copyright-holders:Aaron Giles |
| 3 | //============================================================ |
| 4 | // |
| 5 | // winmain.c - Win32 main program |
| 6 | // |
| 7 | //============================================================ |
| 8 | |
| 9 | // standard windows headers |
| 10 | #define WIN32_LEAN_AND_MEAN |
| 11 | #include <windows.h> |
| 12 | #include <commctrl.h> |
| 13 | #include <mmsystem.h> |
| 14 | #include <tchar.h> |
| 15 | #include <io.h> |
| 16 | |
| 17 | // standard C headers |
| 18 | #include <ctype.h> |
| 19 | #include <stdarg.h> |
| 20 | #include <psapi.h> |
| 21 | #include <dbghelp.h> |
| 22 | |
| 23 | // MAME headers |
| 24 | #include "emu.h" |
| 25 | #include "clifront.h" |
| 26 | #include "emuopts.h" |
| 27 | |
| 28 | // MAMEOS headers |
| 29 | #include "winmain.h" |
| 30 | #include "window.h" |
| 31 | #include "video.h" |
| 32 | #include "input.h" |
| 33 | #include "output.h" |
| 34 | #include "config.h" |
| 35 | #include "osdepend.h" |
| 36 | #include "strconv.h" |
| 37 | #include "winutf8.h" |
| 38 | #include "winutil.h" |
| 39 | #include "debugger.h" |
| 40 | #include "winfile.h" |
| 41 | |
| 42 | #define DEBUG_SLOW_LOCKS 0 |
| 43 | |
| 44 | //************************************************************************** |
| 45 | // MACROS |
| 46 | //************************************************************************** |
| 47 | |
| 48 | #ifdef UNICODE |
| 49 | #define UNICODE_POSTFIX "W" |
| 50 | #else |
| 51 | #define UNICODE_POSTFIX "A" |
| 52 | #endif |
| 53 | |
| 54 | |
| 55 | |
| 56 | //************************************************************************** |
| 57 | // TYPE DEFINITIONS |
| 58 | //************************************************************************** |
| 59 | |
| 60 | template<typename _FunctionPtr> |
| 61 | class dynamic_bind |
| 62 | { |
| 63 | public: |
| 64 | // constructor which looks up the function |
| 65 | dynamic_bind(const TCHAR *dll, const char *symbol) |
| 66 | : m_function(NULL) |
| 67 | { |
| 68 | HMODULE module = LoadLibrary(dll); |
| 69 | if (module != NULL) |
| 70 | m_function = reinterpret_cast<_FunctionPtr>(GetProcAddress(module, symbol)); |
| 71 | } |
| 72 | |
| 73 | // bool to test if the function is NULL or not |
| 74 | operator bool() const { return (m_function != NULL); } |
| 75 | |
| 76 | // dereference to get the underlying pointer |
| 77 | _FunctionPtr operator *() const { return m_function; } |
| 78 | |
| 79 | private: |
| 80 | _FunctionPtr m_function; |
| 81 | }; |
| 82 | |
| 83 | |
| 84 | class stack_walker |
| 85 | { |
| 86 | public: |
| 87 | stack_walker(); |
| 88 | |
| 89 | FPTR ip() const { return m_stackframe.AddrPC.Offset; } |
| 90 | FPTR sp() const { return m_stackframe.AddrStack.Offset; } |
| 91 | FPTR frame() const { return m_stackframe.AddrFrame.Offset; } |
| 92 | |
| 93 | bool reset(); |
| 94 | void reset(CONTEXT &context, HANDLE thread); |
| 95 | bool unwind(); |
| 96 | |
| 97 | private: |
| 98 | HANDLE m_process; |
| 99 | HANDLE m_thread; |
| 100 | STACKFRAME64 m_stackframe; |
| 101 | CONTEXT m_context; |
| 102 | bool m_first; |
| 103 | |
| 104 | dynamic_bind<BOOL (WINAPI *)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64)> |
| 105 | m_stack_walk_64; |
| 106 | dynamic_bind<BOOL (WINAPI *)(HANDLE, LPCTSTR, BOOL)> m_sym_initialize; |
| 107 | dynamic_bind<PVOID (WINAPI *)(HANDLE, DWORD64)> m_sym_function_table_access_64; |
| 108 | dynamic_bind<DWORD64 (WINAPI *)(HANDLE, DWORD64)> m_sym_get_module_base_64; |
| 109 | dynamic_bind<VOID (WINAPI *)(PCONTEXT)> m_rtl_capture_context; |
| 110 | |
| 111 | static bool s_initialized; |
| 112 | }; |
| 113 | |
| 114 | |
| 115 | class symbol_manager |
| 116 | { |
| 117 | public: |
| 118 | // construction/destruction |
| 119 | symbol_manager(const char *argv0); |
| 120 | ~symbol_manager(); |
| 121 | |
| 122 | // getters |
| 123 | FPTR last_base() const { return m_last_base; } |
| 124 | |
| 125 | // core symbol lookup |
| 126 | const char *symbol_for_address(FPTR address); |
| 127 | const char *symbol_for_address(PVOID address) { return symbol_for_address(reinterpret_cast<FPTR>(address)); } |
| 128 | |
| 129 | // force symbols to be cached |
| 130 | void cache_symbols() { scan_file_for_address(0, true); } |
| 131 | |
| 132 | void reset_cache() { m_cache.reset(); } |
| 133 | private: |
| 134 | // internal helpers |
| 135 | bool query_system_for_address(FPTR address); |
| 136 | void scan_file_for_address(FPTR address, bool create_cache); |
| 137 | bool parse_sym_line(const char *line, FPTR &address, std::string &symbol); |
| 138 | bool parse_map_line(const char *line, FPTR &address, std::string &symbol); |
| 139 | void scan_cache_for_address(FPTR address); |
| 140 | void format_symbol(const char *name, UINT32 displacement, const char *filename = NULL, int linenumber = 0); |
| 141 | |
| 142 | static FPTR get_text_section_base(); |
| 143 | |
| 144 | struct cache_entry |
| 145 | { |
| 146 | cache_entry(FPTR address, const char *symbol) : |
| 147 | m_next(NULL), m_address(address), m_name(symbol) { } |
| 148 | cache_entry *next() const { return m_next; } |
| 149 | |
| 150 | cache_entry * m_next; |
| 151 | FPTR m_address; |
| 152 | std::string m_name; |
| 153 | }; |
| 154 | simple_list<cache_entry> m_cache; |
| 155 | |
| 156 | std::string m_mapfile; |
| 157 | std::string m_symfile; |
| 158 | std::string m_buffer; |
| 159 | HANDLE m_process; |
| 160 | FPTR m_last_base; |
| 161 | FPTR m_text_base; |
| 162 | |
| 163 | dynamic_bind<BOOL (WINAPI *)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO)> m_sym_from_addr; |
| 164 | dynamic_bind<BOOL (WINAPI *)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64)> m_sym_get_line_from_addr_64; |
| 165 | }; |
| 166 | |
| 167 | |
| 168 | class sampling_profiler |
| 169 | { |
| 170 | public: |
| 171 | sampling_profiler(UINT32 max_seconds, UINT8 stack_depth); |
| 172 | ~sampling_profiler(); |
| 173 | |
| 174 | void start(); |
| 175 | void stop(); |
| 176 | |
| 177 | // void reset(); |
| 178 | void print_results(symbol_manager &symbols); |
| 179 | |
| 180 | private: |
| 181 | static DWORD WINAPI thread_entry(LPVOID lpParameter); |
| 182 | void thread_run(); |
| 183 | |
| 184 | static int CLIB_DECL compare_address(const void *item1, const void *item2); |
| 185 | static int CLIB_DECL compare_frequency(const void *item1, const void *item2); |
| 186 | |
| 187 | HANDLE m_target_thread; |
| 188 | |
| 189 | HANDLE m_thread; |
| 190 | DWORD m_thread_id; |
| 191 | volatile bool m_thread_exit; |
| 192 | |
| 193 | UINT8 m_stack_depth; |
| 194 | UINT8 m_entry_stride; |
| 195 | std::vector<FPTR> m_buffer; |
| 196 | FPTR * m_buffer_ptr; |
| 197 | FPTR * m_buffer_end; |
| 198 | }; |
| 199 | |
| 200 | //============================================================ |
| 201 | // winui_output_error |
| 202 | //============================================================ |
| 203 | |
| 204 | class winui_output_error : public osd_output |
| 205 | { |
| 206 | public: |
| 207 | virtual void output_callback(osd_output_channel channel, const char *msg, va_list args) |
| 208 | { |
| 209 | if (channel == OSD_OUTPUT_CHANNEL_ERROR) |
| 210 | { |
| 211 | char buffer[1024]; |
| 212 | |
| 213 | // if we are in fullscreen mode, go to windowed mode |
| 214 | if ((video_config.windowed == 0) && (win_window_list != NULL)) |
| 215 | winwindow_toggle_full_screen(); |
| 216 | |
| 217 | vsnprintf(buffer, ARRAY_LENGTH(buffer), msg, args); |
| 218 | win_message_box_utf8(win_window_list ? win_window_list->m_hwnd : NULL, buffer, emulator_info::get_appname(), MB_OK); |
| 219 | } |
| 220 | else |
| 221 | chain_output(channel, msg, args); |
| 222 | } |
| 223 | }; |
| 224 | |
| 225 | |
| 226 | |
| 227 | |
| 228 | //************************************************************************** |
| 229 | // GLOBAL VARIABLES |
| 230 | //************************************************************************** |
| 231 | |
| 232 | // this line prevents globbing on the command line |
| 233 | int _CRT_glob = 0; |
| 234 | |
| 235 | //************************************************************************** |
| 236 | // LOCAL VARIABLES |
| 237 | //************************************************************************** |
| 238 | |
| 239 | static LPTOP_LEVEL_EXCEPTION_FILTER pass_thru_filter; |
| 240 | |
| 241 | static HANDLE watchdog_reset_event; |
| 242 | static HANDLE watchdog_exit_event; |
| 243 | static HANDLE watchdog_thread; |
| 244 | |
| 245 | static running_machine *g_current_machine; |
| 246 | |
| 247 | static int timeresult = !TIMERR_NOERROR; |
| 248 | static TIMECAPS timecaps; |
| 249 | |
| 250 | static sampling_profiler *profiler = NULL; |
| 251 | static symbol_manager *symbols = NULL; |
| 252 | |
| 253 | bool stack_walker::s_initialized = false; |
| 254 | |
| 255 | |
| 256 | //************************************************************************** |
| 257 | // FUNCTION PROTOTYPES |
| 258 | //************************************************************************** |
| 259 | |
| 260 | static BOOL WINAPI control_handler(DWORD type); |
| 261 | static int is_double_click_start(int argc); |
| 262 | static DWORD WINAPI watchdog_thread_entry(LPVOID lpParameter); |
| 263 | static LONG WINAPI exception_filter(struct _EXCEPTION_POINTERS *info); |
| 264 | |
| 265 | |
| 266 | |
| 267 | //************************************************************************** |
| 268 | // OPTIONS |
| 269 | //************************************************************************** |
| 270 | |
| 271 | // struct definitions |
| 272 | const options_entry windows_options::s_option_entries[] = |
| 273 | { |
| 274 | // performance options |
| 275 | { NULL, NULL, OPTION_HEADER, "WINDOWS PERFORMANCE OPTIONS" }, |
| 276 | { WINOPTION_PRIORITY "(-15-1)", "0", OPTION_INTEGER, "thread priority for the main game thread; range from -15 to 1" }, |
| 277 | { WINOPTION_PROFILE, "0", OPTION_INTEGER, "enables profiling, specifying the stack depth to track" }, |
| 278 | |
| 279 | // video options |
| 280 | { NULL, NULL, OPTION_HEADER, "WINDOWS VIDEO OPTIONS" }, |
| 281 | { WINOPTION_MENU, "0", OPTION_BOOLEAN, "enables menu bar if available by UI implementation" }, |
| 282 | |
| 283 | // DirectDraw-specific options |
| 284 | { NULL, NULL, OPTION_HEADER, "DIRECTDRAW-SPECIFIC OPTIONS" }, |
| 285 | { WINOPTION_HWSTRETCH ";hws", "1", OPTION_BOOLEAN, "enables hardware stretching" }, |
| 286 | |
| 287 | // post-processing options |
| 288 | { NULL, NULL, OPTION_HEADER, "DIRECT3D POST-PROCESSING OPTIONS" }, |
| 289 | { WINOPTION_HLSL_ENABLE";hlsl", "0", OPTION_BOOLEAN, "enables HLSL post-processing (PS3.0 required)" }, |
| 290 | { WINOPTION_HLSLPATH, "hlsl", OPTION_STRING, "path to hlsl files" }, |
| 291 | { WINOPTION_HLSL_PRESCALE_X, "0", OPTION_INTEGER, "HLSL pre-scale override factor for X (0 for auto)" }, |
| 292 | { WINOPTION_HLSL_PRESCALE_Y, "0", OPTION_INTEGER, "HLSL pre-scale override factor for Y (0 for auto)" }, |
| 293 | { WINOPTION_HLSL_WRITE, NULL, OPTION_STRING, "enables HLSL AVI writing (huge disk bandwidth suggested)" }, |
| 294 | { WINOPTION_HLSL_SNAP_WIDTH, "2048", OPTION_STRING, "HLSL upscaled-snapshot width" }, |
| 295 | { WINOPTION_HLSL_SNAP_HEIGHT, "1536", OPTION_STRING, "HLSL upscaled-snapshot height" }, |
| 296 | { WINOPTION_SHADOW_MASK_ALPHA";fs_shadwa(0.0-1.0)", "0.0", OPTION_FLOAT, "shadow mask alpha-blend value (1.0 is fully blended, 0.0 is no mask)" }, |
| 297 | { WINOPTION_SHADOW_MASK_TEXTURE";fs_shadwt(0.0-1.0)", "aperture.png", OPTION_STRING, "shadow mask texture name" }, |
| 298 | { WINOPTION_SHADOW_MASK_COUNT_X";fs_shadww", "6", OPTION_INTEGER, "shadow mask tile width, in screen dimensions" }, |
| 299 | { WINOPTION_SHADOW_MASK_COUNT_Y";fs_shadwh", "6", OPTION_INTEGER, "shadow mask tile height, in screen dimensions" }, |
| 300 | { WINOPTION_SHADOW_MASK_USIZE";fs_shadwu(0.0-1.0)", "0.1875", OPTION_FLOAT, "shadow mask texture width, in U/V dimensions" }, |
| 301 | { WINOPTION_SHADOW_MASK_VSIZE";fs_shadwv(0.0-1.0)", "0.1875", OPTION_FLOAT, "shadow mask texture height, in U/V dimensions" }, |
| 302 | { WINOPTION_SHADOW_MASK_UOFFSET";fs_shadwou(-1.0-1.0)", "0.0", OPTION_FLOAT, "shadow mask texture offset, in U direction" }, |
| 303 | { WINOPTION_SHADOW_MASK_VOFFSET";fs_shadwov(-1.0-1.0)", "0.0", OPTION_FLOAT, "shadow mask texture offset, in V direction" }, |
| 304 | { WINOPTION_CURVATURE";fs_curv(0.0-1.0)", "0.0", OPTION_FLOAT, "screen curvature amount" }, |
| 305 | { WINOPTION_ROUND_CORNER";fs_rndc(0.0-1.0)", "0.0", OPTION_FLOAT, "screen round corner amount" }, |
| 306 | { WINOPTION_SMOOTH_BORDER";fs_smob(0.0-1.0)", "0.0", OPTION_FLOAT, "screen smooth border amount" }, |
| 307 | { WINOPTION_REFLECTION";fs_ref(0.0-1.0)", "0.0", OPTION_FLOAT, "screen reflection amount" }, |
| 308 | { WINOPTION_VIGNETTING";fs_vig(0.0-1.0)", "0.0", OPTION_FLOAT, "image vignetting amount" }, |
| 309 | /* Beam-related values below this line*/ |
| 310 | { WINOPTION_SCANLINE_AMOUNT";fs_scanam(0.0-4.0)", "1.0", OPTION_FLOAT, "overall alpha scaling value for scanlines" }, |
| 311 | { WINOPTION_SCANLINE_SCALE";fs_scansc(0.0-4.0)", "1.0", OPTION_FLOAT, "overall height scaling value for scanlines" }, |
| 312 | { WINOPTION_SCANLINE_HEIGHT";fs_scanh(0.0-4.0)", "1.0", OPTION_FLOAT, "individual height scaling value for scanlines" }, |
| 313 | { WINOPTION_SCANLINE_BRIGHT_SCALE";fs_scanbs(0.0-2.0)", "1.0", OPTION_FLOAT, "overall brightness scaling value for scanlines (multiplicative)" }, |
| 314 | { WINOPTION_SCANLINE_BRIGHT_OFFSET";fs_scanbo(0.0-1.0)", "0.0", OPTION_FLOAT, "overall brightness offset value for scanlines (additive)" }, |
| 315 | { WINOPTION_SCANLINE_OFFSET";fs_scanjt(0.0-4.0)", "0.0", OPTION_FLOAT, "overall interlace jitter scaling value for scanlines" }, |
| 316 | { WINOPTION_DEFOCUS";fs_focus", "0.0,0.0", OPTION_STRING, "overall defocus value in screen-relative coords" }, |
| 317 | { WINOPTION_CONVERGE_X";fs_convx", "0.3,0.0,-0.3",OPTION_STRING, "convergence in screen-relative X direction" }, |
| 318 | { WINOPTION_CONVERGE_Y";fs_convy", "0.0,0.3,-0.3",OPTION_STRING, "convergence in screen-relative Y direction" }, |
| 319 | { WINOPTION_RADIAL_CONVERGE_X";fs_rconvx", "0.0,0.0,0.0",OPTION_STRING, "radial convergence in screen-relative X direction" }, |
| 320 | { WINOPTION_RADIAL_CONVERGE_Y";fs_rconvy", "0.0,0.0,0.0",OPTION_STRING, "radial convergence in screen-relative Y direction" }, |
| 321 | /* RGB colorspace convolution below this line */ |
| 322 | { WINOPTION_RED_RATIO";fs_redratio", "1.0,0.0,0.0",OPTION_STRING, "red output signal generated by input signal" }, |
| 323 | { WINOPTION_GRN_RATIO";fs_grnratio", "0.0,1.0,0.0",OPTION_STRING, "green output signal generated by input signal" }, |
| 324 | { WINOPTION_BLU_RATIO";fs_bluratio", "0.0,0.0,1.0",OPTION_STRING, "blue output signal generated by input signal" }, |
| 325 | { WINOPTION_SATURATION";fs_sat(0.0-4.0)", "1.4", OPTION_FLOAT, "saturation scaling value" }, |
| 326 | { WINOPTION_OFFSET";fs_offset", "0.0,0.0,0.0",OPTION_STRING, "signal offset value (additive)" }, |
| 327 | { WINOPTION_SCALE";fs_scale", "0.95,0.95,0.95",OPTION_STRING, "signal scaling value (multiplicative)" }, |
| 328 | { WINOPTION_POWER";fs_power", "0.8,0.8,0.8",OPTION_STRING, "signal power value (exponential)" }, |
| 329 | { WINOPTION_FLOOR";fs_floor", "0.05,0.05,0.05",OPTION_STRING, "signal floor level" }, |
| 330 | { WINOPTION_PHOSPHOR";fs_phosphor", "0.4,0.4,0.4",OPTION_STRING, "phosphorescence decay rate (0.0 is instant, 1.0 is forever)" }, |
| 331 | /* NTSC simulation below this line */ |
| 332 | { NULL, NULL, OPTION_HEADER, "NTSC POST-PROCESSING OPTIONS" }, |
| 333 | { WINOPTION_YIQ_ENABLE";yiq", "0", OPTION_BOOLEAN, "enables YIQ-space HLSL post-processing" }, |
| 334 | { WINOPTION_YIQ_CCVALUE";yiqcc", "3.59754545",OPTION_FLOAT, "Color Carrier frequency for NTSC signal processing" }, |
| 335 | { WINOPTION_YIQ_AVALUE";yiqa", "0.5", OPTION_FLOAT, "A value for NTSC signal processing" }, |
| 336 | { WINOPTION_YIQ_BVALUE";yiqb", "0.5", OPTION_FLOAT, "B value for NTSC signal processing" }, |
| 337 | { WINOPTION_YIQ_OVALUE";yiqo", "1.570796325",OPTION_FLOAT, "Outgoing Color Carrier phase offset for NTSC signal processing" }, |
| 338 | { WINOPTION_YIQ_PVALUE";yiqp", "1.0", OPTION_FLOAT, "Incoming Pixel Clock scaling value for NTSC signal processing" }, |
| 339 | { WINOPTION_YIQ_NVALUE";yiqn", "1.0", OPTION_FLOAT, "Y filter notch width for NTSC signal processing" }, |
| 340 | { WINOPTION_YIQ_YVALUE";yiqy", "6.0", OPTION_FLOAT, "Y filter cutoff frequency for NTSC signal processing" }, |
| 341 | { WINOPTION_YIQ_IVALUE";yiqi", "1.2", OPTION_FLOAT, "I filter cutoff frequency for NTSC signal processing" }, |
| 342 | { WINOPTION_YIQ_QVALUE";yiqq", "0.6", OPTION_FLOAT, "Q filter cutoff frequency for NTSC signal processing" }, |
| 343 | { WINOPTION_YIQ_SCAN_TIME";yiqsc", "52.6", OPTION_FLOAT, "Horizontal scanline duration for NTSC signal processing (in usec)" }, |
| 344 | { WINOPTION_YIQ_PHASE_COUNT";yiqp", "2", OPTION_INTEGER, "Phase Count value for NTSC signal processing" }, |
| 345 | { WINOPTION_YIQ_SCAN_TIME";yiqsc", "52.6", OPTION_FLOAT, "Horizontal scanline duration for NTSC signal processing (in usec)" }, |
| 346 | { WINOPTION_YIQ_PHASE_COUNT";yiqp", "2", OPTION_INTEGER, "Phase Count value for NTSC signal processing" }, |
| 347 | /* Vector simulation below this line */ |
| 348 | { NULL, NULL, OPTION_HEADER, "VECTOR POST-PROCESSING OPTIONS" }, |
| 349 | { WINOPTION_VECTOR_LENGTH_SCALE";veclength", "0.8", OPTION_FLOAT, "How much length affects vector fade" }, |
| 350 | { WINOPTION_VECTOR_LENGTH_RATIO";vecsize", "500.0", OPTION_FLOAT, "Vector fade length (4.0 - vectors fade the most at and above 4 pixels, etc.)" }, |
| 351 | /* Bloom below this line */ |
| 352 | { NULL, NULL, OPTION_HEADER, "BLOOM POST-PROCESSING OPTIONS" }, |
| 353 | { WINOPTION_BLOOM_SCALE, "0.25", OPTION_FLOAT, "Intensity factor for bloom" }, |
| 354 | { WINOPTION_BLOOM_OVERDRIVE, "0.0,0.0,0.0",OPTION_STRING, "Overdrive factor for bloom" }, |
| 355 | { WINOPTION_BLOOM_LEVEL0_WEIGHT, "1.0", OPTION_FLOAT, "Bloom level 0 (full-size target) weight" }, |
| 356 | { WINOPTION_BLOOM_LEVEL1_WEIGHT, "0.21", OPTION_FLOAT, "Bloom level 1 (half-size target) weight" }, |
| 357 | { WINOPTION_BLOOM_LEVEL2_WEIGHT, "0.19", OPTION_FLOAT, "Bloom level 2 (quarter-size target) weight" }, |
| 358 | { WINOPTION_BLOOM_LEVEL3_WEIGHT, "0.17", OPTION_FLOAT, "Bloom level 3 (.) weight" }, |
| 359 | { WINOPTION_BLOOM_LEVEL4_WEIGHT, "0.15", OPTION_FLOAT, "Bloom level 4 (.) weight" }, |
| 360 | { WINOPTION_BLOOM_LEVEL5_WEIGHT, "0.14", OPTION_FLOAT, "Bloom level 5 (.) weight" }, |
| 361 | { WINOPTION_BLOOM_LEVEL6_WEIGHT, "0.13", OPTION_FLOAT, "Bloom level 6 (.) weight" }, |
| 362 | { WINOPTION_BLOOM_LEVEL7_WEIGHT, "0.12", OPTION_FLOAT, "Bloom level 7 (.) weight" }, |
| 363 | { WINOPTION_BLOOM_LEVEL8_WEIGHT, "0.11", OPTION_FLOAT, "Bloom level 8 (.) weight" }, |
| 364 | { WINOPTION_BLOOM_LEVEL9_WEIGHT, "0.10", OPTION_FLOAT, "Bloom level 9 (.) weight" }, |
| 365 | { WINOPTION_BLOOM_LEVEL10_WEIGHT, "0.09", OPTION_FLOAT, "Bloom level 10 (1x1 target) weight" }, |
| 366 | |
| 367 | // full screen options |
| 368 | { NULL, NULL, OPTION_HEADER, "FULL SCREEN OPTIONS" }, |
| 369 | { WINOPTION_TRIPLEBUFFER ";tb", "0", OPTION_BOOLEAN, "enables triple buffering" }, |
| 370 | { WINOPTION_FULLSCREENBRIGHTNESS ";fsb(0.1-2.0)", "1.0", OPTION_FLOAT, "brightness value in full screen mode" }, |
| 371 | { WINOPTION_FULLSCREENCONTRAST ";fsc(0.1-2.0)", "1.0", OPTION_FLOAT, "contrast value in full screen mode" }, |
| 372 | { WINOPTION_FULLSCREENGAMMA ";fsg(0.1-3.0)", "1.0", OPTION_FLOAT, "gamma value in full screen mode" }, |
| 373 | |
| 374 | // input options |
| 375 | { NULL, NULL, OPTION_HEADER, "INPUT DEVICE OPTIONS" }, |
| 376 | { WINOPTION_GLOBAL_INPUTS ";global_inputs", "0", OPTION_BOOLEAN, "enables global inputs" }, |
| 377 | { WINOPTION_DUAL_LIGHTGUN ";dual", "0", OPTION_BOOLEAN, "enables dual lightgun input" }, |
| 378 | |
| 379 | { NULL } |
| 380 | }; |
| 381 | |
| 382 | //************************************************************************** |
| 383 | // MAIN ENTRY POINT |
| 384 | //************************************************************************** |
| 385 | |
| 386 | |
| 387 | //============================================================ |
| 388 | // utf8_main |
| 389 | //============================================================ |
| 390 | |
| 391 | int main(int argc, char *argv[]) |
| 392 | { |
| 393 | // use small output buffers on non-TTYs (i.e. pipes) |
| 394 | if (!isatty(fileno(stdout))) |
| 395 | setvbuf(stdout, (char *) NULL, _IOFBF, 64); |
| 396 | if (!isatty(fileno(stderr))) |
| 397 | setvbuf(stderr, (char *) NULL, _IOFBF, 64); |
| 398 | |
| 399 | // initialize common controls |
| 400 | InitCommonControls(); |
| 401 | |
| 402 | // set a handler to catch ctrl-c |
| 403 | SetConsoleCtrlHandler(control_handler, TRUE); |
| 404 | |
| 405 | // allocate symbols |
| 406 | symbol_manager local_symbols(argv[0]); |
| 407 | symbols = &local_symbols; |
| 408 | |
| 409 | // set up exception handling |
| 410 | pass_thru_filter = SetUnhandledExceptionFilter(exception_filter); |
| 411 | SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); |
| 412 | |
| 413 | // enable stack crawls for asserts |
| 414 | extern void (*s_debugger_stack_crawler)(); |
| 415 | s_debugger_stack_crawler = winmain_dump_stack; |
| 416 | |
| 417 | |
| 418 | // parse config and cmdline options |
| 419 | DWORD result = 0; |
| 420 | { |
| 421 | windows_options options; |
| 422 | windows_osd_interface osd(options); |
| 423 | // if we're a GUI app, out errors to message boxes |
| 424 | // Initialize this after the osd interface so that we are first in the |
| 425 | // output order |
| 426 | winui_output_error winerror; |
| 427 | if (win_is_gui_application() || is_double_click_start(argc)) |
| 428 | { |
| 429 | // if we are a GUI app, output errors to message boxes |
| 430 | osd_output::push(&winerror); |
| 431 | // make sure any console window that opened on our behalf is nuked |
| 432 | FreeConsole(); |
| 433 | } |
| 434 | osd.register_options(); |
| 435 | cli_frontend frontend(options, osd); |
| 436 | result = frontend.execute(argc, argv); |
| 437 | osd_output::pop(&winerror); |
| 438 | } |
| 439 | // free symbols |
| 440 | symbols = NULL; |
| 441 | return result; |
| 442 | } |
| 443 | |
| 444 | |
| 445 | //============================================================ |
| 446 | // windows_options |
| 447 | //============================================================ |
| 448 | |
| 449 | windows_options::windows_options() |
| 450 | : osd_options() |
| 451 | { |
| 452 | add_entries(s_option_entries); |
| 453 | } |
| 454 | |
| 455 | |
| 456 | //============================================================ |
| 457 | // control_handler |
| 458 | //============================================================ |
| 459 | |
| 460 | static BOOL WINAPI control_handler(DWORD type) |
| 461 | { |
| 462 | // indicate to the user that we detected something |
| 463 | switch (type) |
| 464 | { |
| 465 | case CTRL_C_EVENT: fprintf(stderr, "Caught Ctrl+C"); break; |
| 466 | case CTRL_BREAK_EVENT: fprintf(stderr, "Caught Ctrl+break"); break; |
| 467 | case CTRL_CLOSE_EVENT: fprintf(stderr, "Caught console close"); break; |
| 468 | case CTRL_LOGOFF_EVENT: fprintf(stderr, "Caught logoff"); break; |
| 469 | case CTRL_SHUTDOWN_EVENT: fprintf(stderr, "Caught shutdown"); break; |
| 470 | default: fprintf(stderr, "Caught unexpected console event"); break; |
| 471 | } |
| 472 | |
| 473 | // if we don't have a machine yet, or if we are handling ctrl+c/ctrl+break, |
| 474 | // just terminate hard, without throwing or handling any atexit stuff |
| 475 | if (g_current_machine == NULL || type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT) |
| 476 | { |
| 477 | fprintf(stderr, ", exiting\n"); |
| 478 | TerminateProcess(GetCurrentProcess(), MAMERR_FATALERROR); |
| 479 | } |
| 480 | |
| 481 | // all other situations attempt to do a clean exit |
| 482 | else |
| 483 | { |
| 484 | fprintf(stderr, ", exit requested\n"); |
| 485 | g_current_machine->schedule_exit(); |
| 486 | } |
| 487 | |
| 488 | // in all cases we handled it |
| 489 | return TRUE; |
| 490 | } |
| 491 | |
| 492 | |
| 493 | |
| 494 | |
| 495 | //============================================================ |
| 496 | // output_oslog |
| 497 | //============================================================ |
| 498 | |
| 499 | static void output_oslog(const running_machine &machine, const char *buffer) |
| 500 | { |
| 501 | if (IsDebuggerPresent()) |
| 502 | win_output_debug_string_utf8(buffer); |
| 503 | } |
| 504 | |
| 505 | |
| 506 | //============================================================ |
| 507 | // constructor |
| 508 | //============================================================ |
| 509 | |
| 510 | windows_osd_interface::windows_osd_interface(windows_options &options) |
| 511 | : osd_common_t(options), m_options(options) |
| 512 | { |
| 513 | } |
| 514 | |
| 515 | |
| 516 | //============================================================ |
| 517 | // destructor |
| 518 | //============================================================ |
| 519 | |
| 520 | windows_osd_interface::~windows_osd_interface() |
| 521 | { |
| 522 | } |
| 523 | |
| 524 | |
| 525 | //============================================================ |
| 526 | // video_register |
| 527 | //============================================================ |
| 528 | |
| 529 | void windows_osd_interface::video_register() |
| 530 | { |
| 531 | video_options_add("gdi", NULL); |
| 532 | video_options_add("ddraw", NULL); |
| 533 | video_options_add("d3d", NULL); |
| 534 | video_options_add("bgfx", NULL); |
| 535 | //video_options_add("auto", NULL); // making d3d video default one |
| 536 | } |
| 537 | |
| 538 | //============================================================ |
| 539 | // init |
| 540 | //============================================================ |
| 541 | |
| 542 | void windows_osd_interface::init(running_machine &machine) |
| 543 | { |
| 544 | // call our parent |
| 545 | osd_common_t::init(machine); |
| 546 | |
| 547 | const char *stemp; |
| 548 | windows_options &options = downcast<windows_options &>(machine.options()); |
| 549 | |
| 550 | // determine if we are benchmarking, and adjust options appropriately |
| 551 | int bench = options.bench(); |
| 552 | std::string error_string; |
| 553 | if (bench > 0) |
| 554 | { |
| 555 | options.set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM, error_string); |
| 556 | options.set_value(OSDOPTION_SOUND, "none", OPTION_PRIORITY_MAXIMUM, error_string); |
| 557 | options.set_value(OSDOPTION_VIDEO, "none", OPTION_PRIORITY_MAXIMUM, error_string); |
| 558 | options.set_value(OPTION_SECONDS_TO_RUN, bench, OPTION_PRIORITY_MAXIMUM, error_string); |
| 559 | assert(error_string.empty()); |
| 560 | } |
| 561 | |
| 562 | // determine if we are profiling, and adjust options appropriately |
| 563 | int profile = options.profile(); |
| 564 | if (profile > 0) |
| 565 | { |
| 566 | options.set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM, error_string); |
| 567 | options.set_value(OSDOPTION_MULTITHREADING, false, OPTION_PRIORITY_MAXIMUM, error_string); |
| 568 | options.set_value(OSDOPTION_NUMPROCESSORS, 1, OPTION_PRIORITY_MAXIMUM, error_string); |
| 569 | assert(error_string.empty()); |
| 570 | } |
| 571 | |
| 572 | // thread priority |
| 573 | if (!(machine.debug_flags & DEBUG_FLAG_OSD_ENABLED)) |
| 574 | SetThreadPriority(GetCurrentThread(), options.priority()); |
| 575 | |
| 576 | // get number of processors |
| 577 | stemp = options.numprocessors(); |
| 578 | |
| 579 | osd_num_processors = 0; |
| 580 | |
| 581 | if (strcmp(stemp, "auto") != 0) |
| 582 | { |
| 583 | osd_num_processors = atoi(stemp); |
| 584 | if (osd_num_processors < 1) |
| 585 | { |
| 586 | osd_printf_warning("Warning: numprocessors < 1 doesn't make much sense. Assuming auto ...\n"); |
| 587 | osd_num_processors = 0; |
| 588 | } |
| 589 | } |
| 590 | |
| 591 | // initialize the subsystems |
| 592 | osd_common_t::init_subsystems(); |
| 593 | |
| 594 | // notify listeners of screen configuration |
| 595 | std::string tempstring; |
| 596 | for (win_window_info *info = win_window_list; info != NULL; info = info->m_next) |
| 597 | { |
| 598 | strprintf(tempstring, "Orientation(%s)", info->m_monitor->devicename()); |
| 599 | output_set_value(tempstring.c_str(), info->m_targetorient); |
| 600 | } |
| 601 | |
| 602 | // hook up the debugger log |
| 603 | if (options.oslog()) |
| 604 | machine.add_logerror_callback(output_oslog); |
| 605 | |
| 606 | // crank up the multimedia timer resolution to its max |
| 607 | // this gives the system much finer timeslices |
| 608 | timeresult = timeGetDevCaps(&timecaps, sizeof(timecaps)); |
| 609 | if (timeresult == TIMERR_NOERROR) |
| 610 | timeBeginPeriod(timecaps.wPeriodMin); |
| 611 | |
| 612 | // if a watchdog thread is requested, create one |
| 613 | int watchdog = options.watchdog(); |
| 614 | if (watchdog != 0) |
| 615 | { |
| 616 | watchdog_reset_event = CreateEvent(NULL, FALSE, FALSE, NULL); |
| 617 | assert_always(watchdog_reset_event != NULL, "Failed to create watchdog reset event"); |
| 618 | watchdog_exit_event = CreateEvent(NULL, TRUE, FALSE, NULL); |
| 619 | assert_always(watchdog_exit_event != NULL, "Failed to create watchdog exit event"); |
| 620 | watchdog_thread = CreateThread(NULL, 0, watchdog_thread_entry, (LPVOID)(FPTR)watchdog, 0, NULL); |
| 621 | assert_always(watchdog_thread != NULL, "Failed to create watchdog thread"); |
| 622 | } |
| 623 | |
| 624 | // create and start the profiler |
| 625 | if (profile > 0) |
| 626 | { |
| 627 | profiler = global_alloc(sampling_profiler(1000, profile - 1)); |
| 628 | profiler->start(); |
| 629 | } |
| 630 | |
| 631 | // initialize sockets |
| 632 | win_init_sockets(); |
| 633 | |
| 634 | // note the existence of a machine |
| 635 | g_current_machine = &machine; |
| 636 | } |
| 637 | |
| 638 | |
| 639 | //============================================================ |
| 640 | // osd_exit |
| 641 | //============================================================ |
| 642 | |
| 643 | void windows_osd_interface::osd_exit() |
| 644 | { |
| 645 | // no longer have a machine |
| 646 | g_current_machine = NULL; |
| 647 | |
| 648 | // cleanup sockets |
| 649 | win_cleanup_sockets(); |
| 650 | |
| 651 | osd_common_t::osd_exit(); |
| 652 | |
| 653 | // take down the watchdog thread if it exists |
| 654 | if (watchdog_thread != NULL) |
| 655 | { |
| 656 | SetEvent(watchdog_exit_event); |
| 657 | WaitForSingleObject(watchdog_thread, INFINITE); |
| 658 | CloseHandle(watchdog_reset_event); |
| 659 | CloseHandle(watchdog_exit_event); |
| 660 | CloseHandle(watchdog_thread); |
| 661 | watchdog_reset_event = NULL; |
| 662 | watchdog_exit_event = NULL; |
| 663 | watchdog_thread = NULL; |
| 664 | } |
| 665 | |
| 666 | // stop the profiler |
| 667 | if (profiler != NULL) |
| 668 | { |
| 669 | profiler->stop(); |
| 670 | profiler->print_results(*symbols); |
| 671 | global_free(profiler); |
| 672 | } |
| 673 | |
| 674 | // restore the timer resolution |
| 675 | if (timeresult == TIMERR_NOERROR) |
| 676 | timeEndPeriod(timecaps.wPeriodMin); |
| 677 | |
| 678 | // one last pass at events |
| 679 | winwindow_process_events(machine(), 0, 0); |
| 680 | } |
| 681 | |
| 682 | //============================================================ |
| 683 | // winmain_dump_stack |
| 684 | //============================================================ |
| 685 | |
| 686 | void winmain_dump_stack() |
| 687 | { |
| 688 | // set up the stack walker |
| 689 | stack_walker walker; |
| 690 | if (!walker.reset()) |
| 691 | return; |
| 692 | |
| 693 | // walk the stack |
| 694 | while (walker.unwind()) |
| 695 | fprintf(stderr, " %p: %p%s\n", (void *)walker.frame(), (void *)walker.ip(), (symbols == NULL) ? "" : symbols->symbol_for_address(walker.ip())); |
| 696 | } |
| 697 | |
| 698 | |
| 699 | //============================================================ |
| 700 | // check_for_double_click_start |
| 701 | //============================================================ |
| 702 | |
| 703 | static int is_double_click_start(int argc) |
| 704 | { |
| 705 | STARTUPINFO startup_info = { sizeof(STARTUPINFO) }; |
| 706 | |
| 707 | // determine our startup information |
| 708 | GetStartupInfo(&startup_info); |
| 709 | |
| 710 | // try to determine if MAME was simply double-clicked |
| 711 | return (argc <= 1 && startup_info.dwFlags && !(startup_info.dwFlags & STARTF_USESTDHANDLES)); |
| 712 | } |
| 713 | |
| 714 | |
| 715 | //============================================================ |
| 716 | // watchdog_thread_entry |
| 717 | //============================================================ |
| 718 | |
| 719 | static DWORD WINAPI watchdog_thread_entry(LPVOID lpParameter) |
| 720 | { |
| 721 | DWORD timeout = (int)(FPTR)lpParameter * 1000; |
| 722 | |
| 723 | while (TRUE) |
| 724 | { |
| 725 | HANDLE handle_list[2]; |
| 726 | DWORD wait_result; |
| 727 | |
| 728 | // wait for either a reset or an exit, or a timeout |
| 729 | handle_list[0] = watchdog_reset_event; |
| 730 | handle_list[1] = watchdog_exit_event; |
| 731 | wait_result = WaitForMultipleObjects(2, handle_list, FALSE, timeout); |
| 732 | |
| 733 | // on a reset, just loop around and re-wait |
| 734 | if (wait_result == WAIT_OBJECT_0 + 0) |
| 735 | continue; |
| 736 | |
| 737 | // on an exit, break out |
| 738 | if (wait_result == WAIT_OBJECT_0 + 1) |
| 739 | break; |
| 740 | |
| 741 | // on a timeout, kill the process |
| 742 | if (wait_result == WAIT_TIMEOUT) |
| 743 | { |
| 744 | fprintf(stderr, "Terminating due to watchdog timeout\n"); |
| 745 | fflush(stderr); |
| 746 | TerminateProcess(GetCurrentProcess(), -1); |
| 747 | } |
| 748 | } |
| 749 | return EXCEPTION_CONTINUE_SEARCH; |
| 750 | } |
| 751 | |
| 752 | |
| 753 | //============================================================ |
| 754 | // winmain_watchdog_ping |
| 755 | //============================================================ |
| 756 | |
| 757 | void winmain_watchdog_ping(void) |
| 758 | { |
| 759 | // if we have a watchdog, reset it |
| 760 | if (watchdog_reset_event != NULL) |
| 761 | SetEvent(watchdog_reset_event); |
| 762 | } |
| 763 | |
| 764 | |
| 765 | //============================================================ |
| 766 | // exception_filter |
| 767 | //============================================================ |
| 768 | |
| 769 | static LONG WINAPI exception_filter(struct _EXCEPTION_POINTERS *info) |
| 770 | { |
| 771 | static const struct |
| 772 | { |
| 773 | DWORD code; |
| 774 | const char *string; |
| 775 | } exception_table[] = |
| 776 | { |
| 777 | { EXCEPTION_ACCESS_VIOLATION, "ACCESS VIOLATION" }, |
| 778 | { EXCEPTION_DATATYPE_MISALIGNMENT, "DATATYPE MISALIGNMENT" }, |
| 779 | { EXCEPTION_BREAKPOINT, "BREAKPOINT" }, |
| 780 | { EXCEPTION_SINGLE_STEP, "SINGLE STEP" }, |
| 781 | { EXCEPTION_ARRAY_BOUNDS_EXCEEDED, "ARRAY BOUNDS EXCEEDED" }, |
| 782 | { EXCEPTION_FLT_DENORMAL_OPERAND, "FLOAT DENORMAL OPERAND" }, |
| 783 | { EXCEPTION_FLT_DIVIDE_BY_ZERO, "FLOAT DIVIDE BY ZERO" }, |
| 784 | { EXCEPTION_FLT_INEXACT_RESULT, "FLOAT INEXACT RESULT" }, |
| 785 | { EXCEPTION_FLT_INVALID_OPERATION, "FLOAT INVALID OPERATION" }, |
| 786 | { EXCEPTION_FLT_OVERFLOW, "FLOAT OVERFLOW" }, |
| 787 | { EXCEPTION_FLT_STACK_CHECK, "FLOAT STACK CHECK" }, |
| 788 | { EXCEPTION_FLT_UNDERFLOW, "FLOAT UNDERFLOW" }, |
| 789 | { EXCEPTION_INT_DIVIDE_BY_ZERO, "INTEGER DIVIDE BY ZERO" }, |
| 790 | { EXCEPTION_INT_OVERFLOW, "INTEGER OVERFLOW" }, |
| 791 | { EXCEPTION_PRIV_INSTRUCTION, "PRIVILEGED INSTRUCTION" }, |
| 792 | { EXCEPTION_IN_PAGE_ERROR, "IN PAGE ERROR" }, |
| 793 | { EXCEPTION_ILLEGAL_INSTRUCTION, "ILLEGAL INSTRUCTION" }, |
| 794 | { EXCEPTION_NONCONTINUABLE_EXCEPTION,"NONCONTINUABLE EXCEPTION" }, |
| 795 | { EXCEPTION_STACK_OVERFLOW, "STACK OVERFLOW" }, |
| 796 | { EXCEPTION_INVALID_DISPOSITION, "INVALID DISPOSITION" }, |
| 797 | { EXCEPTION_GUARD_PAGE, "GUARD PAGE VIOLATION" }, |
| 798 | { EXCEPTION_INVALID_HANDLE, "INVALID HANDLE" }, |
| 799 | { 0, "UNKNOWN EXCEPTION" } |
| 800 | }; |
| 801 | static int already_hit = 0; |
| 802 | int i; |
| 803 | |
| 804 | // if we're hitting this recursively, just exit |
| 805 | if (already_hit) |
| 806 | return EXCEPTION_CONTINUE_SEARCH; |
| 807 | already_hit = 1; |
| 808 | |
| 809 | // flush any debugging traces that were live |
| 810 | debugger_flush_all_traces_on_abnormal_exit(); |
| 811 | |
| 812 | // find our man |
| 813 | for (i = 0; exception_table[i].code != 0; i++) |
| 814 | if (info->ExceptionRecord->ExceptionCode == exception_table[i].code) |
| 815 | break; |
| 816 | |
| 817 | // print the exception type and address |
| 818 | fprintf(stderr, "\n-----------------------------------------------------\n"); |
| 819 | fprintf(stderr, "Exception at EIP=%p%s: %s\n", info->ExceptionRecord->ExceptionAddress, |
| 820 | symbols->symbol_for_address((FPTR)info->ExceptionRecord->ExceptionAddress), exception_table[i].string); |
| 821 | |
| 822 | // for access violations, print more info |
| 823 | if (info->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) |
| 824 | fprintf(stderr, "While attempting to %s memory at %p\n", |
| 825 | info->ExceptionRecord->ExceptionInformation[0] ? "write" : "read", |
| 826 | (void *)info->ExceptionRecord->ExceptionInformation[1]); |
| 827 | |
| 828 | // print the state of the CPU |
| 829 | fprintf(stderr, "-----------------------------------------------------\n"); |
| 830 | #ifdef PTR64 |
| 831 | fprintf(stderr, "RAX=%p RBX=%p RCX=%p RDX=%p\n", |
| 832 | (void *)info->ContextRecord->Rax, |
| 833 | (void *)info->ContextRecord->Rbx, |
| 834 | (void *)info->ContextRecord->Rcx, |
| 835 | (void *)info->ContextRecord->Rdx); |
| 836 | fprintf(stderr, "RSI=%p RDI=%p RBP=%p RSP=%p\n", |
| 837 | (void *)info->ContextRecord->Rsi, |
| 838 | (void *)info->ContextRecord->Rdi, |
| 839 | (void *)info->ContextRecord->Rbp, |
| 840 | (void *)info->ContextRecord->Rsp); |
| 841 | fprintf(stderr, " R8=%p R9=%p R10=%p R11=%p\n", |
| 842 | (void *)info->ContextRecord->R8, |
| 843 | (void *)info->ContextRecord->R9, |
| 844 | (void *)info->ContextRecord->R10, |
| 845 | (void *)info->ContextRecord->R11); |
| 846 | fprintf(stderr, "R12=%p R13=%p R14=%p R15=%p\n", |
| 847 | (void *)info->ContextRecord->R12, |
| 848 | (void *)info->ContextRecord->R13, |
| 849 | (void *)info->ContextRecord->R14, |
| 850 | (void *)info->ContextRecord->R15); |
| 851 | #else |
| 852 | fprintf(stderr, "EAX=%p EBX=%p ECX=%p EDX=%p\n", |
| 853 | (void *)info->ContextRecord->Eax, |
| 854 | (void *)info->ContextRecord->Ebx, |
| 855 | (void *)info->ContextRecord->Ecx, |
| 856 | (void *)info->ContextRecord->Edx); |
| 857 | fprintf(stderr, "ESI=%p EDI=%p EBP=%p ESP=%p\n", |
| 858 | (void *)info->ContextRecord->Esi, |
| 859 | (void *)info->ContextRecord->Edi, |
| 860 | (void *)info->ContextRecord->Ebp, |
| 861 | (void *)info->ContextRecord->Esp); |
| 862 | #endif |
| 863 | |
| 864 | stack_walker walker; |
| 865 | walker.reset(*info->ContextRecord, GetCurrentThread()); |
| 866 | |
| 867 | // reprint the actual exception address |
| 868 | fprintf(stderr, "-----------------------------------------------------\n"); |
| 869 | fprintf(stderr, "Stack crawl:\n"); |
| 870 | |
| 871 | // walk the stack |
| 872 | while (walker.unwind()) |
| 873 | fprintf(stderr, " %p: %p%s\n", (void *)walker.frame(), (void *)walker.ip(), (symbols == NULL) ? "" : symbols->symbol_for_address(walker.ip())); |
| 874 | |
| 875 | // flush stderr, so the data is actually written when output is being redirected |
| 876 | fflush(stderr); |
| 877 | |
| 878 | // exit |
| 879 | return EXCEPTION_CONTINUE_SEARCH; |
| 880 | } |
| 881 | |
| 882 | |
| 883 | //************************************************************************** |
| 884 | // STACK WALKER |
| 885 | //************************************************************************** |
| 886 | |
| 887 | //------------------------------------------------- |
| 888 | // stack_walker - constructor |
| 889 | //------------------------------------------------- |
| 890 | |
| 891 | stack_walker::stack_walker() |
| 892 | : m_process(GetCurrentProcess()), |
| 893 | m_thread(GetCurrentThread()), |
| 894 | m_first(true), |
| 895 | m_stack_walk_64(TEXT("dbghelp.dll"), "StackWalk64"), |
| 896 | m_sym_initialize(TEXT("dbghelp.dll"), "SymInitialize"), |
| 897 | m_sym_function_table_access_64(TEXT("dbghelp.dll"), "SymFunctionTableAccess64"), |
| 898 | m_sym_get_module_base_64(TEXT("dbghelp.dll"), "SymGetModuleBase64"), |
| 899 | m_rtl_capture_context(TEXT("kernel32.dll"), "RtlCaptureContext") |
| 900 | { |
| 901 | // zap the structs |
| 902 | memset(&m_stackframe, 0, sizeof(m_stackframe)); |
| 903 | memset(&m_context, 0, sizeof(m_context)); |
| 904 | |
| 905 | // initialize the symbols |
| 906 | if (!s_initialized && m_sym_initialize && m_stack_walk_64 && m_sym_function_table_access_64 && m_sym_get_module_base_64) |
| 907 | { |
| 908 | (*m_sym_initialize)(m_process, NULL, TRUE); |
| 909 | s_initialized = true; |
| 910 | } |
| 911 | } |
| 912 | |
| 913 | |
| 914 | //------------------------------------------------- |
| 915 | // reset - set up a new context |
| 916 | //------------------------------------------------- |
| 917 | |
| 918 | bool stack_walker::reset() |
| 919 | { |
| 920 | // set up the initial state |
| 921 | if (!m_rtl_capture_context) |
| 922 | return false; |
| 923 | (*m_rtl_capture_context)(&m_context); |
| 924 | m_thread = GetCurrentThread(); |
| 925 | m_first = true; |
| 926 | |
| 927 | // initialize the stackframe |
| 928 | memset(&m_stackframe, 0, sizeof(m_stackframe)); |
| 929 | m_stackframe.AddrPC.Mode = AddrModeFlat; |
| 930 | m_stackframe.AddrFrame.Mode = AddrModeFlat; |
| 931 | m_stackframe.AddrStack.Mode = AddrModeFlat; |
| 932 | |
| 933 | // pull architecture-specific fields from the context |
| 934 | #ifdef PTR64 |
| 935 | m_stackframe.AddrPC.Offset = m_context.Rip; |
| 936 | m_stackframe.AddrFrame.Offset = m_context.Rsp; |
| 937 | m_stackframe.AddrStack.Offset = m_context.Rsp; |
| 938 | #else |
| 939 | m_stackframe.AddrPC.Offset = m_context.Eip; |
| 940 | m_stackframe.AddrFrame.Offset = m_context.Ebp; |
| 941 | m_stackframe.AddrStack.Offset = m_context.Esp; |
| 942 | #endif |
| 943 | return true; |
| 944 | } |
| 945 | |
| 946 | void stack_walker::reset(CONTEXT &initial, HANDLE thread) |
| 947 | { |
| 948 | // set up the initial state |
| 949 | m_context = initial; |
| 950 | m_thread = thread; |
| 951 | m_first = true; |
| 952 | |
| 953 | // initialize the stackframe |
| 954 | memset(&m_stackframe, 0, sizeof(m_stackframe)); |
| 955 | m_stackframe.AddrPC.Mode = AddrModeFlat; |
| 956 | m_stackframe.AddrFrame.Mode = AddrModeFlat; |
| 957 | m_stackframe.AddrStack.Mode = AddrModeFlat; |
| 958 | |
| 959 | // pull architecture-specific fields from the context |
| 960 | #ifdef PTR64 |
| 961 | m_stackframe.AddrPC.Offset = m_context.Rip; |
| 962 | m_stackframe.AddrFrame.Offset = m_context.Rsp; |
| 963 | m_stackframe.AddrStack.Offset = m_context.Rsp; |
| 964 | #else |
| 965 | m_stackframe.AddrPC.Offset = m_context.Eip; |
| 966 | m_stackframe.AddrFrame.Offset = m_context.Ebp; |
| 967 | m_stackframe.AddrStack.Offset = m_context.Esp; |
| 968 | #endif |
| 969 | } |
| 970 | |
| 971 | |
| 972 | //------------------------------------------------- |
| 973 | // unwind - unwind a single level |
| 974 | //------------------------------------------------- |
| 975 | |
| 976 | bool stack_walker::unwind() |
| 977 | { |
| 978 | // if we were able to initialize, then we have everything we need |
| 979 | if (s_initialized) |
| 980 | { |
| 981 | #ifdef PTR64 |
| 982 | return (*m_stack_walk_64)(IMAGE_FILE_MACHINE_AMD64, m_process, m_thread, &m_stackframe, &m_context, NULL, *m_sym_function_table_access_64, *m_sym_get_module_base_64, NULL); |
| 983 | #else |
| 984 | return (*m_stack_walk_64)(IMAGE_FILE_MACHINE_I386, m_process, m_thread, &m_stackframe, &m_context, NULL, *m_sym_function_table_access_64, *m_sym_get_module_base_64, NULL); |
| 985 | #endif |
| 986 | } |
| 987 | |
| 988 | // otherwise, fake the first unwind, which will just return info from the context |
| 989 | else |
| 990 | { |
| 991 | bool result = m_first; |
| 992 | m_first = false; |
| 993 | return result; |
| 994 | } |
| 995 | } |
| 996 | |
| 997 | |
| 998 | |
| 999 | //************************************************************************** |
| 1000 | // SYMBOL MANAGER |
| 1001 | //************************************************************************** |
| 1002 | |
| 1003 | //------------------------------------------------- |
| 1004 | // symbol_manager - constructor |
| 1005 | //------------------------------------------------- |
| 1006 | |
| 1007 | symbol_manager::symbol_manager(const char *argv0) |
| 1008 | : m_mapfile(argv0), |
| 1009 | m_symfile(argv0), |
| 1010 | m_process(GetCurrentProcess()), |
| 1011 | m_last_base(0), |
| 1012 | m_text_base(0), |
| 1013 | m_sym_from_addr(TEXT("dbghelp.dll"), "SymFromAddr"), |
| 1014 | m_sym_get_line_from_addr_64(TEXT("dbghelp.dll"), "SymGetLineFromAddr64") |
| 1015 | { |
| 1016 | #ifdef __GNUC__ |
| 1017 | // compute the name of the mapfile |
| 1018 | int extoffs = m_mapfile.find_last_of('.'); |
| 1019 | if (extoffs != -1) |
| 1020 | m_mapfile.substr(0, extoffs); |
| 1021 | m_mapfile.append(".map"); |
| 1022 | |
| 1023 | // and the name of the symfile |
| 1024 | extoffs = m_symfile.find_last_of('.'); |
| 1025 | if (extoffs != -1) |
| 1026 | m_symfile = m_symfile.substr(0, extoffs); |
| 1027 | m_symfile.append(".sym"); |
| 1028 | |
| 1029 | // figure out the base of the .text section |
| 1030 | m_text_base = get_text_section_base(); |
| 1031 | #endif |
| 1032 | |
| 1033 | // expand the buffer to be decently large up front |
| 1034 | strprintf(m_buffer,"%500s", ""); |
| 1035 | } |
| 1036 | |
| 1037 | |
| 1038 | //------------------------------------------------- |
| 1039 | // ~symbol_manager - destructor |
| 1040 | //------------------------------------------------- |
| 1041 | |
| 1042 | symbol_manager::~symbol_manager() |
| 1043 | { |
| 1044 | } |
| 1045 | |
| 1046 | |
| 1047 | //------------------------------------------------- |
| 1048 | // symbol_for_address - return a symbol by looking |
| 1049 | // it up either in the cache or by scanning the |
| 1050 | // file |
| 1051 | //------------------------------------------------- |
| 1052 | |
| 1053 | const char *symbol_manager::symbol_for_address(FPTR address) |
| 1054 | { |
| 1055 | // default the buffer |
| 1056 | m_buffer.assign(" (not found)"); |
| 1057 | m_last_base = 0; |
| 1058 | |
| 1059 | // first try to do it using system APIs |
| 1060 | if (!query_system_for_address(address)) |
| 1061 | { |
| 1062 | // if that fails, scan the cache if we have one |
| 1063 | if (m_cache.first() != NULL) |
| 1064 | scan_cache_for_address(address); |
| 1065 | |
| 1066 | // or else try to open a sym/map file and find it there |
| 1067 | else |
| 1068 | scan_file_for_address(address, false); |
| 1069 | } |
| 1070 | return m_buffer.c_str(); |
| 1071 | } |
| 1072 | |
| 1073 | |
| 1074 | //------------------------------------------------- |
| 1075 | // query_system_for_address - ask the system to |
| 1076 | // look up our address |
| 1077 | //------------------------------------------------- |
| 1078 | |
| 1079 | bool symbol_manager::query_system_for_address(FPTR address) |
| 1080 | { |
| 1081 | // need at least the sym_from_addr API |
| 1082 | if (!m_sym_from_addr) |
| 1083 | return false; |
| 1084 | |
| 1085 | BYTE info_buffer[sizeof(SYMBOL_INFO) + 256] = { 0 }; |
| 1086 | SYMBOL_INFO &info = *reinterpret_cast<SYMBOL_INFO *>(&info_buffer[0]); |
| 1087 | DWORD64 displacement; |
| 1088 | |
| 1089 | // even through the struct says TCHAR, we actually get back an ANSI string here |
| 1090 | info.SizeOfStruct = sizeof(info); |
| 1091 | info.MaxNameLen = sizeof(info_buffer) - sizeof(info); |
| 1092 | if ((*m_sym_from_addr)(m_process, address, &displacement, &info)) |
| 1093 | { |
| 1094 | // try to get source info as well; again we are returned an ANSI string |
| 1095 | IMAGEHLP_LINE64 lineinfo = { sizeof(lineinfo) }; |
| 1096 | DWORD linedisp; |
| 1097 | if (m_sym_get_line_from_addr_64 && (*m_sym_get_line_from_addr_64)(m_process, address, &linedisp, &lineinfo)) |
| 1098 | format_symbol(info.Name, displacement, lineinfo.FileName, lineinfo.LineNumber); |
| 1099 | else |
| 1100 | format_symbol(info.Name, displacement); |
| 1101 | |
| 1102 | // set the last base |
| 1103 | m_last_base = address - displacement; |
| 1104 | return true; |
| 1105 | } |
| 1106 | return false; |
| 1107 | } |
| 1108 | |
| 1109 | |
| 1110 | //------------------------------------------------- |
| 1111 | // scan_file_for_address - walk either the map |
| 1112 | // or symbol files and find the best match for |
| 1113 | // the given address, optionally creating a cache |
| 1114 | // along the way |
| 1115 | //------------------------------------------------- |
| 1116 | |
| 1117 | void symbol_manager::scan_file_for_address(FPTR address, bool create_cache) |
| 1118 | { |
| 1119 | bool is_symfile = false; |
| 1120 | FILE *srcfile = NULL; |
| 1121 | |
| 1122 | #ifdef __GNUC__ |
| 1123 | // see if we have a symbol file (gcc only) |
| 1124 | srcfile = fopen(m_symfile.c_str(), "r"); |
| 1125 | is_symfile = (srcfile != NULL); |
| 1126 | #endif |
| 1127 | |
| 1128 | // if not, see if we have a map file |
| 1129 | if (srcfile == NULL) |
| 1130 | srcfile = fopen(m_mapfile.c_str(), "r"); |
| 1131 | |
| 1132 | // if not, fail |
| 1133 | if (srcfile == NULL) |
| 1134 | return; |
| 1135 | |
| 1136 | // reset the best info |
| 1137 | std::string best_symbol; |
| 1138 | FPTR best_addr = 0; |
| 1139 | |
| 1140 | // parse the file, looking for valid entries |
| 1141 | std::string symbol; |
| 1142 | char line[1024]; |
| 1143 | while (fgets(line, sizeof(line) - 1, srcfile)) |
| 1144 | { |
| 1145 | // parse the line looking for an interesting symbol |
| 1146 | FPTR addr = 0; |
| 1147 | bool valid = is_symfile ? parse_sym_line(line, addr, symbol) : parse_map_line(line, addr, symbol); |
| 1148 | |
| 1149 | // if we got one, see if this is the best |
| 1150 | if (valid) |
| 1151 | { |
| 1152 | // if this is the best one so far, remember it |
| 1153 | if (addr <= address && addr > best_addr) |
| 1154 | { |
| 1155 | best_addr = addr; |
| 1156 | best_symbol = symbol; |
| 1157 | } |
| 1158 | |
| 1159 | // also create a cache entry if we can |
| 1160 | if (create_cache) |
| 1161 | m_cache.append(*global_alloc(cache_entry(addr, symbol.c_str()))); |
| 1162 | } |
| 1163 | } |
| 1164 | |
| 1165 | // close the file |
| 1166 | fclose(srcfile); |
| 1167 | |
| 1168 | // format the symbol and remember the last base |
| 1169 | format_symbol(best_symbol.c_str(), address - best_addr); |
| 1170 | m_last_base = best_addr; |
| 1171 | } |
| 1172 | |
| 1173 | |
| 1174 | //------------------------------------------------- |
| 1175 | // scan_cache_for_address - walk the cache to |
| 1176 | // find the best match for the given address |
| 1177 | //------------------------------------------------- |
| 1178 | |
| 1179 | void symbol_manager::scan_cache_for_address(FPTR address) |
| 1180 | { |
| 1181 | // reset the best info |
| 1182 | std::string best_symbol; |
| 1183 | FPTR best_addr = 0; |
| 1184 | |
| 1185 | // walk the cache, looking for valid entries |
| 1186 | for (cache_entry *entry = m_cache.first(); entry != NULL; entry = entry->next()) |
| 1187 | |
| 1188 | // if this is the best one so far, remember it |
| 1189 | if (entry->m_address <= address && entry->m_address > best_addr) |
| 1190 | { |
| 1191 | best_addr = entry->m_address; |
| 1192 | best_symbol = entry->m_name; |
| 1193 | } |
| 1194 | |
| 1195 | // format the symbol and remember the last base |
| 1196 | format_symbol(best_symbol.c_str(), address - best_addr); |
| 1197 | m_last_base = best_addr; |
| 1198 | } |
| 1199 | |
| 1200 | |
| 1201 | //------------------------------------------------- |
| 1202 | // parse_sym_line - parse a line from a sym file |
| 1203 | // which is just the output of objdump |
| 1204 | //------------------------------------------------- |
| 1205 | |
| 1206 | bool symbol_manager::parse_sym_line(const char *line, FPTR &address, std::string &symbol) |
| 1207 | { |
| 1208 | #ifdef __GNUC__ |
| 1209 | /* |
| 1210 | 32-bit gcc symbol line: |
| 1211 | [271778](sec 1)(fl 0x00)(ty 20)(scl 3) (nx 0) 0x007df675 line_to_symbol(char const*, unsigned int&, bool) |
| 1212 | |
| 1213 | 64-bit gcc symbol line: |
| 1214 | [271775](sec 1)(fl 0x00)(ty 20)(scl 3) (nx 0) 0x00000000008dd1e9 line_to_symbol(char const*, unsigned long long&, bool) |
| 1215 | */ |
| 1216 | |
| 1217 | // first look for a (ty) entry |
| 1218 | const char *type = strstr(line, "(ty 20)"); |
| 1219 | if (type == NULL) |
| 1220 | return false; |
| 1221 | |
| 1222 | // scan forward in the line to find the address |
| 1223 | bool in_parens = false; |
| 1224 | for (const char *chptr = type; *chptr != 0; chptr++) |
| 1225 | { |
| 1226 | // track open/close parentheses |
| 1227 | if (*chptr == '(') |
| 1228 | in_parens = true; |
| 1229 | else if (*chptr == ')') |
| 1230 | in_parens = false; |
| 1231 | |
| 1232 | // otherwise, look for an 0x address |
| 1233 | else if (!in_parens && *chptr == '0' && chptr[1] == 'x') |
| 1234 | { |
| 1235 | // make sure we can get an address |
| 1236 | void *temp; |
| 1237 | if (sscanf(chptr, "0x%p", &temp) != 1) |
| 1238 | return false; |
| 1239 | address = m_text_base + reinterpret_cast<FPTR>(temp); |
| 1240 | |
| 1241 | // skip forward until we're past the space |
| 1242 | while (*chptr != 0 && !isspace(*chptr)) |
| 1243 | chptr++; |
| 1244 | |
| 1245 | // extract the symbol name |
| 1246 | strtrimspace(symbol.assign(chptr)); |
| 1247 | return (symbol.length() > 0); |
| 1248 | } |
| 1249 | } |
| 1250 | #endif |
| 1251 | return false; |
| 1252 | } |
| 1253 | |
| 1254 | |
| 1255 | //------------------------------------------------- |
| 1256 | // parse_map_line - parse a line from a linker- |
| 1257 | // generated map file |
| 1258 | //------------------------------------------------- |
| 1259 | |
| 1260 | bool symbol_manager::parse_map_line(const char *line, FPTR &address, std::string &symbol) |
| 1261 | { |
| 1262 | #ifdef __GNUC__ |
| 1263 | /* |
| 1264 | 32-bit gcc map line: |
| 1265 | 0x0089cb00 nbmj9195_palette_r(_address_space const*, unsigned int) |
| 1266 | |
| 1267 | 64-bit gcc map line: |
| 1268 | 0x0000000000961afc nbmj9195_palette_r(_address_space const*, unsigned int) |
| 1269 | */ |
| 1270 | |
| 1271 | // find a matching start |
| 1272 | if (strncmp(line, " 0x", 18) == 0) |
| 1273 | { |
| 1274 | // make sure we can get an address |
| 1275 | void *temp; |
| 1276 | if (sscanf(&line[16], "0x%p", &temp) != 1) |
| 1277 | return false; |
| 1278 | address = reinterpret_cast<FPTR>(temp); |
| 1279 | |
| 1280 | // skip forward until we're past the space |
| 1281 | const char *chptr = &line[16]; |
| 1282 | while (*chptr != 0 && !isspace(*chptr)) |
| 1283 | chptr++; |
| 1284 | |
| 1285 | // extract the symbol name |
| 1286 | strtrimspace(symbol.assign(chptr)); |
| 1287 | return (symbol.length() > 0); |
| 1288 | } |
| 1289 | #endif |
| 1290 | return false; |
| 1291 | } |
| 1292 | |
| 1293 | |
| 1294 | //------------------------------------------------- |
| 1295 | // format_symbol - common symbol formatting |
| 1296 | //------------------------------------------------- |
| 1297 | |
| 1298 | void symbol_manager::format_symbol(const char *name, UINT32 displacement, const char *filename, int linenumber) |
| 1299 | { |
| 1300 | // start with the address and offset |
| 1301 | strprintf(m_buffer, " (%s", name); |
| 1302 | if (displacement != 0) |
| 1303 | strcatprintf(m_buffer, "+0x%04x", (UINT32)displacement); |
| 1304 | |
| 1305 | // append file/line if present |
| 1306 | if (filename != NULL) |
| 1307 | strcatprintf(m_buffer, ", %s:%d", filename, linenumber); |
| 1308 | |
| 1309 | // close up the string |
| 1310 | m_buffer.append(")"); |
| 1311 | } |
| 1312 | |
| 1313 | |
| 1314 | //------------------------------------------------- |
| 1315 | // get_text_section_base - figure out the base |
| 1316 | // of the .text section |
| 1317 | //------------------------------------------------- |
| 1318 | |
| 1319 | FPTR symbol_manager::get_text_section_base() |
| 1320 | { |
| 1321 | dynamic_bind<PIMAGE_SECTION_HEADER (WINAPI *)(PIMAGE_NT_HEADERS, PVOID, ULONG)> image_rva_to_section(TEXT("dbghelp.dll"), "ImageRvaToSection"); |
| 1322 | dynamic_bind<PIMAGE_NT_HEADERS (WINAPI *)(PVOID)> image_nt_header(TEXT("dbghelp.dll"), "ImageNtHeader"); |
| 1323 | |
| 1324 | // start with the image base |
| 1325 | PVOID base = reinterpret_cast<PVOID>(GetModuleHandleUni()); |
| 1326 | assert(base != NULL); |
| 1327 | |
| 1328 | // make sure we have the functions we need |
| 1329 | if (image_nt_header && image_rva_to_section) |
| 1330 | { |
| 1331 | // get the NT header |
| 1332 | PIMAGE_NT_HEADERS headers = (*image_nt_header)(base); |
| 1333 | assert(headers != NULL); |
| 1334 | |
| 1335 | // look ourself up (assuming we are in the .text section) |
| 1336 | PIMAGE_SECTION_HEADER section = (*image_rva_to_section)(headers, base, reinterpret_cast<FPTR>(get_text_section_base) - reinterpret_cast<FPTR>(base)); |
| 1337 | if (section != NULL) |
| 1338 | return reinterpret_cast<FPTR>(base) + section->VirtualAddress; |
| 1339 | } |
| 1340 | |
| 1341 | // fallback to returning the image base (wrong) |
| 1342 | return reinterpret_cast<FPTR>(base); |
| 1343 | } |
| 1344 | |
| 1345 | |
| 1346 | |
| 1347 | //************************************************************************** |
| 1348 | // SAMPLING PROFILER |
| 1349 | //************************************************************************** |
| 1350 | |
| 1351 | //------------------------------------------------- |
| 1352 | // sampling_profiler - constructor |
| 1353 | //------------------------------------------------- |
| 1354 | |
| 1355 | sampling_profiler::sampling_profiler(UINT32 max_seconds, UINT8 stack_depth = 0) |
| 1356 | : m_thread(NULL), |
| 1357 | m_thread_id(0), |
| 1358 | m_thread_exit(false), |
| 1359 | m_stack_depth(stack_depth), |
| 1360 | m_entry_stride(stack_depth + 2), |
| 1361 | m_buffer(max_seconds * 1000 * m_entry_stride), |
| 1362 | m_buffer_ptr(&m_buffer[0]), |
| 1363 | m_buffer_end(&m_buffer[0] + max_seconds * 1000 * m_entry_stride) |
| 1364 | { |
| 1365 | } |
| 1366 | |
| 1367 | |
| 1368 | //------------------------------------------------- |
| 1369 | // sampling_profiler - destructor |
| 1370 | //------------------------------------------------- |
| 1371 | |
| 1372 | sampling_profiler::~sampling_profiler() |
| 1373 | { |
| 1374 | } |
| 1375 | |
| 1376 | |
| 1377 | //------------------------------------------------- |
| 1378 | // start - begin gathering profiling information |
| 1379 | //------------------------------------------------- |
| 1380 | |
| 1381 | void sampling_profiler::start() |
| 1382 | { |
| 1383 | // do the dance to get a handle to ourself |
| 1384 | BOOL result = DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &m_target_thread, |
| 1385 | THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION, FALSE, 0); |
| 1386 | assert_always(result, "Failed to get thread handle for main thread"); |
| 1387 | |
| 1388 | // reset the exit flag |
| 1389 | m_thread_exit = false; |
| 1390 | |
| 1391 | // start the thread |
| 1392 | m_thread = CreateThread(NULL, 0, thread_entry, (LPVOID)this, 0, &m_thread_id); |
| 1393 | assert_always(m_thread != NULL, "Failed to create profiler thread\n"); |
| 1394 | |
| 1395 | // max out the priority |
| 1396 | SetThreadPriority(m_thread, THREAD_PRIORITY_TIME_CRITICAL); |
| 1397 | } |
| 1398 | |
| 1399 | |
| 1400 | //------------------------------------------------- |
| 1401 | // stop - stop gathering profiling information |
| 1402 | //------------------------------------------------- |
| 1403 | |
| 1404 | void sampling_profiler::stop() |
| 1405 | { |
| 1406 | // set the flag and wait a couple of seconds (max) |
| 1407 | m_thread_exit = true; |
| 1408 | WaitForSingleObject(m_thread, 2000); |
| 1409 | |
| 1410 | // regardless, close the handle |
| 1411 | CloseHandle(m_thread); |
| 1412 | } |
| 1413 | |
| 1414 | |
| 1415 | //------------------------------------------------- |
| 1416 | // compare_address - compare two entries by their |
| 1417 | // bucket address |
| 1418 | //------------------------------------------------- |
| 1419 | |
| 1420 | int CLIB_DECL sampling_profiler::compare_address(const void *item1, const void *item2) |
| 1421 | { |
| 1422 | const FPTR *entry1 = reinterpret_cast<const FPTR *>(item1); |
| 1423 | const FPTR *entry2 = reinterpret_cast<const FPTR *>(item2); |
| 1424 | int mincount = MIN(entry1[0], entry2[0]); |
| 1425 | |
| 1426 | // sort in order of: bucket, caller, caller's caller, etc. |
| 1427 | for (int index = 1; index <= mincount; index++) |
| 1428 | if (entry1[index] != entry2[index]) |
| 1429 | return entry1[index] - entry2[index]; |
| 1430 | |
| 1431 | // if we match to the end, sort by the depth of the stack |
| 1432 | return entry1[0] - entry2[0]; |
| 1433 | } |
| 1434 | |
| 1435 | |
| 1436 | //------------------------------------------------- |
| 1437 | // compare_frequency - compare two entries by |
| 1438 | // their frequency of occurrence |
| 1439 | //------------------------------------------------- |
| 1440 | |
| 1441 | int CLIB_DECL sampling_profiler::compare_frequency(const void *item1, const void *item2) |
| 1442 | { |
| 1443 | const FPTR *entry1 = reinterpret_cast<const FPTR *>(item1); |
| 1444 | const FPTR *entry2 = reinterpret_cast<const FPTR *>(item2); |
| 1445 | |
| 1446 | // sort by frequency, then by address |
| 1447 | if (entry1[0] != entry2[0]) |
| 1448 | return entry2[0] - entry1[0]; |
| 1449 | return entry1[1] - entry2[1]; |
| 1450 | } |
| 1451 | |
| 1452 | |
| 1453 | //------------------------------------------------- |
| 1454 | // print_results - output the results |
| 1455 | //------------------------------------------------- |
| 1456 | |
| 1457 | void sampling_profiler::print_results(symbol_manager &symbols) |
| 1458 | { |
| 1459 | // cache the symbols |
| 1460 | symbols.cache_symbols(); |
| 1461 | |
| 1462 | // step 1: find the base of each entry |
| 1463 | for (FPTR *current = &m_buffer[0]; current < m_buffer_ptr; current += m_entry_stride) |
| 1464 | { |
| 1465 | assert(current[0] >= 1 && current[0] < m_entry_stride); |
| 1466 | |
| 1467 | // convert the sampled PC to its function base as a bucket |
| 1468 | symbols.symbol_for_address(current[1]); |
| 1469 | current[1] = symbols.last_base(); |
| 1470 | } |
| 1471 | |
| 1472 | // step 2: sort the results |
| 1473 | qsort(&m_buffer[0], (m_buffer_ptr - &m_buffer[0]) / m_entry_stride, m_entry_stride * sizeof(FPTR), compare_address); |
| 1474 | |
| 1475 | // step 3: count and collapse unique entries |
| 1476 | UINT32 total_count = 0; |
| 1477 | for (FPTR *current = &m_buffer[0]; current < m_buffer_ptr; ) |
| 1478 | { |
| 1479 | int count = 1; |
| 1480 | FPTR *scan; |
| 1481 | for (scan = current + m_entry_stride; scan < m_buffer_ptr; scan += m_entry_stride) |
| 1482 | { |
| 1483 | if (compare_address(current, scan) != 0) |
| 1484 | break; |
| 1485 | scan[0] = 0; |
| 1486 | count++; |
| 1487 | } |
| 1488 | current[0] = count; |
| 1489 | total_count += count; |
| 1490 | current = scan; |
| 1491 | } |
| 1492 | |
| 1493 | // step 4: sort the results again, this time by frequency |
| 1494 | qsort(&m_buffer[0], (m_buffer_ptr - &m_buffer[0]) / m_entry_stride, m_entry_stride * sizeof(FPTR), compare_frequency); |
| 1495 | |
| 1496 | // step 5: print the results |
| 1497 | UINT32 num_printed = 0; |
| 1498 | for (FPTR *current = &m_buffer[0]; current < m_buffer_ptr && num_printed < 30; current += m_entry_stride) |
| 1499 | { |
| 1500 | // once we hit 0 frequency, we're done |
| 1501 | if (current[0] == 0) |
| 1502 | break; |
| 1503 | |
| 1504 | // output the result |
| 1505 | printf("%4.1f%% - %6d : %p%s\n", (double)current[0] * 100.0 / (double)total_count, (UINT32)current[0], reinterpret_cast<void *>(current[1]), symbols.symbol_for_address(current[1])); |
| 1506 | for (int index = 2; index < m_entry_stride; index++) |
| 1507 | { |
| 1508 | if (current[index] == 0) |
| 1509 | break; |
| 1510 | printf(" %p%s\n", reinterpret_cast<void *>(current[index]), symbols.symbol_for_address(current[index])); |
| 1511 | } |
| 1512 | printf("\n"); |
| 1513 | num_printed++; |
| 1514 | } |
| 1515 | symbols.reset_cache(); |
| 1516 | } |
| 1517 | |
| 1518 | |
| 1519 | //------------------------------------------------- |
| 1520 | // thread_entry - thread entry stub |
| 1521 | //------------------------------------------------- |
| 1522 | |
| 1523 | DWORD WINAPI sampling_profiler::thread_entry(LPVOID lpParameter) |
| 1524 | { |
| 1525 | reinterpret_cast<sampling_profiler *>(lpParameter)->thread_run(); |
| 1526 | return 0; |
| 1527 | } |
| 1528 | |
| 1529 | |
| 1530 | //------------------------------------------------- |
| 1531 | // thread_run - sampling thread |
| 1532 | //------------------------------------------------- |
| 1533 | |
| 1534 | void sampling_profiler::thread_run() |
| 1535 | { |
| 1536 | CONTEXT context; |
| 1537 | memset(&context, 0, sizeof(context)); |
| 1538 | |
| 1539 | // loop until done |
| 1540 | stack_walker walker; |
| 1541 | while (!m_thread_exit && m_buffer_ptr < m_buffer_end) |
| 1542 | { |
| 1543 | // pause the main thread and get its context |
| 1544 | SuspendThread(m_target_thread); |
| 1545 | context.ContextFlags = CONTEXT_FULL; |
| 1546 | GetThreadContext(m_target_thread, &context); |
| 1547 | |
| 1548 | // first entry is a count |
| 1549 | FPTR *count = m_buffer_ptr++; |
| 1550 | *count = 0; |
| 1551 | |
| 1552 | // iterate over the frames until we run out or hit an error |
| 1553 | walker.reset(context, m_target_thread); |
| 1554 | int frame; |
| 1555 | for (frame = 0; frame <= m_stack_depth && walker.unwind(); frame++) |
| 1556 | { |
| 1557 | *m_buffer_ptr++ = walker.ip(); |
| 1558 | *count += 1; |
| 1559 | } |
| 1560 | |
| 1561 | // fill in any missing parts with NULLs |
| 1562 | for (; frame <= m_stack_depth; frame++) |
| 1563 | *m_buffer_ptr++ = 0; |
| 1564 | |
| 1565 | // resume the thread |
| 1566 | ResumeThread(m_target_thread); |
| 1567 | |
| 1568 | // sleep for 1ms |
| 1569 | Sleep(1); |
| 1570 | } |
| 1571 | } |