~ubuntu-branches/ubuntu/raring/mame/raring-proposed

« back to all changes in this revision

Viewing changes to mess/src/emu/screen.c

  • Committer: Package Import Robot
  • Author(s): Jordi Mallach, Jordi Mallach, Emmanuel Kasper
  • Date: 2011-12-19 22:56:27 UTC
  • mfrom: (0.1.2)
  • Revision ID: package-import@ubuntu.com-20111219225627-ub5oga1oys4ogqzm
Tags: 0.144-1
[ Jordi Mallach ]
* Fix syntax errors in DEP5 copyright file (lintian).
* Use a versioned copyright Format specification field.
* Update Vcs-* URLs.
* Move transitional packages to the new metapackages section, and make
  them priority extra.
* Remove references to GNU/Linux and MESS sources from copyright.
* Add build variables for s390x.
* Use .xz tarballs as it cuts 4MB for the upstream sources.
* Add nplayers.ini as a patch. Update copyright file to add CC-BY-SA-3.0.

[ Emmanuel Kasper ]
* New upstream release. Closes: #651538.
* Add Free Desktop compliant png icons of various sizes taken from
  the hydroxygen iconset
* Mess is now built from a new source package, to avoid possible source
  incompatibilities between mame and the mess overlay.
* Mame-tools are not built from the mame source package anymore, but
  from the mess source package

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/***************************************************************************
2
 
 
3
 
    screen.c
4
 
 
5
 
    Core MAME screen device.
6
 
 
7
 
****************************************************************************
8
 
 
9
 
    Copyright Aaron Giles
10
 
    All rights reserved.
11
 
 
12
 
    Redistribution and use in source and binary forms, with or without
13
 
    modification, are permitted provided that the following conditions are
14
 
    met:
15
 
 
16
 
        * Redistributions of source code must retain the above copyright
17
 
          notice, this list of conditions and the following disclaimer.
18
 
        * Redistributions in binary form must reproduce the above copyright
19
 
          notice, this list of conditions and the following disclaimer in
20
 
          the documentation and/or other materials provided with the
21
 
          distribution.
22
 
        * Neither the name 'MAME' nor the names of its contributors may be
23
 
          used to endorse or promote products derived from this software
24
 
          without specific prior written permission.
25
 
 
26
 
    THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
27
 
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28
 
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29
 
    DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
30
 
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31
 
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32
 
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33
 
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
34
 
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
35
 
    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36
 
    POSSIBILITY OF SUCH DAMAGE.
37
 
 
38
 
***************************************************************************/
39
 
 
40
 
#include "emu.h"
41
 
#include "emuopts.h"
42
 
#include "png.h"
43
 
#include "rendutil.h"
44
 
 
45
 
 
46
 
 
47
 
//**************************************************************************
48
 
//  DEBUGGING
49
 
//**************************************************************************
50
 
 
51
 
#define VERBOSE                                         (0)
52
 
#define LOG_PARTIAL_UPDATES(x)          do { if (VERBOSE) logerror x; } while (0)
53
 
 
54
 
 
55
 
 
56
 
//**************************************************************************
57
 
//  GLOBAL VARIABLES
58
 
//**************************************************************************
59
 
 
60
 
// device type definition
61
 
const device_type SCREEN = &device_creator<screen_device>;
62
 
 
63
 
const attotime screen_device::DEFAULT_FRAME_PERIOD(attotime::from_hz(DEFAULT_FRAME_RATE));
64
 
 
65
 
 
66
 
 
67
 
//**************************************************************************
68
 
//  SCREEN DEVICE
69
 
//**************************************************************************
70
 
 
71
 
//-------------------------------------------------
72
 
//  screen_device - constructor
73
 
//-------------------------------------------------
74
 
 
75
 
screen_device::screen_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
76
 
        : device_t(mconfig, SCREEN, "Video Screen", tag, owner, clock),
77
 
          m_type(SCREEN_TYPE_RASTER),
78
 
          m_oldstyle_vblank_supplied(false),
79
 
          m_refresh(0),
80
 
          m_vblank(0),
81
 
          m_format(BITMAP_FORMAT_INVALID),
82
 
          m_xoffset(0.0f),
83
 
          m_yoffset(0.0f),
84
 
          m_xscale(1.0f),
85
 
          m_yscale(1.0f),
86
 
          m_screen_update(NULL),
87
 
          m_screen_eof(NULL),
88
 
          m_container(NULL),
89
 
          m_width(100),
90
 
          m_height(100),
91
 
          m_burnin(NULL),
92
 
          m_curbitmap(0),
93
 
          m_curtexture(0),
94
 
          m_texture_format(0),
95
 
          m_changed(true),
96
 
          m_last_partial_scan(0),
97
 
          m_screen_overlay_bitmap(NULL),
98
 
          m_frame_period(DEFAULT_FRAME_PERIOD.as_attoseconds()),
99
 
          m_scantime(1),
100
 
          m_pixeltime(1),
101
 
          m_vblank_period(0),
102
 
          m_vblank_start_time(attotime::zero),
103
 
          m_vblank_end_time(attotime::zero),
104
 
          m_vblank_begin_timer(NULL),
105
 
          m_vblank_end_timer(NULL),
106
 
          m_scanline0_timer(NULL),
107
 
          m_scanline_timer(NULL),
108
 
          m_frame_number(0),
109
 
          m_partial_updates_this_frame(0)
110
 
{
111
 
        m_visarea.min_x = m_visarea.min_y = 0;
112
 
        m_visarea.max_x = m_width - 1;
113
 
        m_visarea.max_y = m_height - 1;
114
 
        memset(m_texture, 0, sizeof(m_texture));
115
 
        memset(m_bitmap, 0, sizeof(m_bitmap));
116
 
}
117
 
 
118
 
 
119
 
//-------------------------------------------------
120
 
//  ~screen_device - destructor
121
 
//-------------------------------------------------
122
 
 
123
 
screen_device::~screen_device()
124
 
{
125
 
}
126
 
 
127
 
 
128
 
//-------------------------------------------------
129
 
//  static_set_format - configuration helper
130
 
//  to set the bitmap format
131
 
//-------------------------------------------------
132
 
 
133
 
void screen_device::static_set_format(device_t &device, bitmap_format format)
134
 
{
135
 
        screen_device &screen = downcast<screen_device &>(device);
136
 
        screen.m_format = format;
137
 
}
138
 
 
139
 
 
140
 
//-------------------------------------------------
141
 
//  static_set_type - configuration helper
142
 
//  to set the screen type
143
 
//-------------------------------------------------
144
 
 
145
 
void screen_device::static_set_type(device_t &device, screen_type_enum type)
146
 
{
147
 
        screen_device &screen = downcast<screen_device &>(device);
148
 
        screen.m_type = type;
149
 
}
150
 
 
151
 
 
152
 
//-------------------------------------------------
153
 
//  static_set_raw - configuration helper
154
 
//  to set the raw screen parameters
155
 
//-------------------------------------------------
156
 
 
157
 
void screen_device::static_set_raw(device_t &device, UINT32 pixclock, UINT16 htotal, UINT16 hbend, UINT16 hbstart, UINT16 vtotal, UINT16 vbend, UINT16 vbstart)
158
 
{
159
 
        screen_device &screen = downcast<screen_device &>(device);
160
 
        screen.m_refresh = HZ_TO_ATTOSECONDS(pixclock) * htotal * vtotal;
161
 
        screen.m_vblank = screen.m_refresh / vtotal * (vtotal - (vbstart - vbend));
162
 
        screen.m_width = htotal;
163
 
        screen.m_height = vtotal;
164
 
        screen.m_visarea.min_x = hbend;
165
 
        screen.m_visarea.max_x = hbstart - 1;
166
 
        screen.m_visarea.min_y = vbend;
167
 
        screen.m_visarea.max_y = vbstart - 1;
168
 
}
169
 
 
170
 
 
171
 
//-------------------------------------------------
172
 
//  static_set_refresh - configuration helper
173
 
//  to set the refresh rate
174
 
//-------------------------------------------------
175
 
 
176
 
void screen_device::static_set_refresh(device_t &device, attoseconds_t rate)
177
 
{
178
 
        screen_device &screen = downcast<screen_device &>(device);
179
 
        screen.m_refresh = rate;
180
 
}
181
 
 
182
 
 
183
 
//-------------------------------------------------
184
 
//  static_set_vblank_time - configuration helper
185
 
//  to set the VBLANK duration
186
 
//-------------------------------------------------
187
 
 
188
 
void screen_device::static_set_vblank_time(device_t &device, attoseconds_t time)
189
 
{
190
 
        screen_device &screen = downcast<screen_device &>(device);
191
 
        screen.m_vblank = time;
192
 
        screen.m_oldstyle_vblank_supplied = true;
193
 
}
194
 
 
195
 
 
196
 
//-------------------------------------------------
197
 
//  static_set_size - configuration helper to set
198
 
//  the width/height of the screen
199
 
//-------------------------------------------------
200
 
 
201
 
void screen_device::static_set_size(device_t &device, UINT16 width, UINT16 height)
202
 
{
203
 
        screen_device &screen = downcast<screen_device &>(device);
204
 
        screen.m_width = width;
205
 
        screen.m_height = height;
206
 
}
207
 
 
208
 
 
209
 
//-------------------------------------------------
210
 
//  static_set_visarea - configuration helper to
211
 
//  set the visible area of the screen
212
 
//-------------------------------------------------
213
 
 
214
 
void screen_device::static_set_visarea(device_t &device, INT16 minx, INT16 maxx, INT16 miny, INT16 maxy)
215
 
{
216
 
        screen_device &screen = downcast<screen_device &>(device);
217
 
        screen.m_visarea.min_x = minx;
218
 
        screen.m_visarea.max_x = maxx;
219
 
        screen.m_visarea.min_y = miny;
220
 
        screen.m_visarea.max_y = maxy;
221
 
}
222
 
 
223
 
 
224
 
//-------------------------------------------------
225
 
//  static_set_default_position - configuration
226
 
//  helper to set the default position and scale
227
 
//  factors for the screen
228
 
//-------------------------------------------------
229
 
 
230
 
void screen_device::static_set_default_position(device_t &device, double xscale, double xoffs, double yscale, double yoffs)
231
 
{
232
 
        screen_device &screen = downcast<screen_device &>(device);
233
 
        screen.m_xscale = xscale;
234
 
        screen.m_xoffset = xoffs;
235
 
        screen.m_yscale = yscale;
236
 
        screen.m_yoffset = yoffs;
237
 
}
238
 
 
239
 
 
240
 
//-------------------------------------------------
241
 
//  static_set_screen_update - set the legacy
242
 
//  screen update callback in the device
243
 
//  configuration
244
 
//-------------------------------------------------
245
 
 
246
 
void screen_device::static_set_screen_update(device_t &device, screen_update_func callback)
247
 
{
248
 
        downcast<screen_device &>(device).m_screen_update = callback;
249
 
}
250
 
 
251
 
 
252
 
//-------------------------------------------------
253
 
//  static_set_screen_eof - set the legacy
254
 
//  screen eof callback in the device
255
 
//  configuration
256
 
//-------------------------------------------------
257
 
 
258
 
void screen_device::static_set_screen_eof(device_t &device, screen_eof_func callback)
259
 
{
260
 
        downcast<screen_device &>(device).m_screen_eof = callback;
261
 
}
262
 
 
263
 
 
264
 
//-------------------------------------------------
265
 
//  device_validity_check - verify device
266
 
//  configuration
267
 
//-------------------------------------------------
268
 
 
269
 
bool screen_device::device_validity_check(emu_options &options, const game_driver &driver) const
270
 
{
271
 
        bool error = false;
272
 
 
273
 
        // sanity check dimensions
274
 
        if (m_width <= 0 || m_height <= 0)
275
 
        {
276
 
                mame_printf_error("%s: %s screen '%s' has invalid display dimensions\n", driver.source_file, driver.name, tag());
277
 
                error = true;
278
 
        }
279
 
 
280
 
        // sanity check display area
281
 
        if (m_type != SCREEN_TYPE_VECTOR)
282
 
        {
283
 
                if ((m_visarea.max_x < m_visarea.min_x) ||
284
 
                        (m_visarea.max_y < m_visarea.min_y) ||
285
 
                        (m_visarea.max_x >= m_width) ||
286
 
                        (m_visarea.max_y >= m_height))
287
 
                {
288
 
                        mame_printf_error("%s: %s screen '%s' has an invalid display area\n", driver.source_file, driver.name, tag());
289
 
                        error = true;
290
 
                }
291
 
 
292
 
                // sanity check screen formats
293
 
                if (m_format != BITMAP_FORMAT_INDEXED16 &&
294
 
                        m_format != BITMAP_FORMAT_RGB15 &&
295
 
                        m_format != BITMAP_FORMAT_RGB32)
296
 
                {
297
 
                        mame_printf_error("%s: %s screen '%s' has unsupported format\n", driver.source_file, driver.name, tag());
298
 
                        error = true;
299
 
                }
300
 
        }
301
 
 
302
 
        // check for zero frame rate
303
 
        if (m_refresh == 0)
304
 
        {
305
 
                mame_printf_error("%s: %s screen '%s' has a zero refresh rate\n", driver.source_file, driver.name, tag());
306
 
                error = true;
307
 
        }
308
 
        return error;
309
 
}
310
 
 
311
 
 
312
 
//-------------------------------------------------
313
 
//  device_start - device-specific startup
314
 
//-------------------------------------------------
315
 
 
316
 
void screen_device::device_start()
317
 
{
318
 
        // configure the default cliparea
319
 
        render_container::user_settings settings;
320
 
        m_container->get_user_settings(settings);
321
 
        settings.m_xoffset = m_xoffset;
322
 
        settings.m_yoffset = m_yoffset;
323
 
        settings.m_xscale = m_xscale;
324
 
        settings.m_yscale = m_yscale;
325
 
        m_container->set_user_settings(settings);
326
 
 
327
 
        // allocate the VBLANK timers
328
 
        m_vblank_begin_timer = machine().scheduler().timer_alloc(FUNC(static_vblank_begin_callback), (void *)this);
329
 
        m_vblank_end_timer = machine().scheduler().timer_alloc(FUNC(static_vblank_end_callback), (void *)this);
330
 
 
331
 
        // allocate a timer to reset partial updates
332
 
        m_scanline0_timer = machine().scheduler().timer_alloc(FUNC(static_scanline0_callback), (void *)this);
333
 
 
334
 
        // allocate a timer to generate per-scanline updates
335
 
        if ((machine().config().m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0)
336
 
                m_scanline_timer = machine().scheduler().timer_alloc(FUNC(static_scanline_update_callback), (void *)this);
337
 
 
338
 
        // configure the screen with the default parameters
339
 
        configure(m_width, m_height, m_visarea, m_refresh);
340
 
 
341
 
        // reset VBLANK timing
342
 
        m_vblank_start_time = attotime::zero;
343
 
        m_vblank_end_time = attotime(0, m_vblank_period);
344
 
 
345
 
        // start the timer to generate per-scanline updates
346
 
        if ((machine().config().m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0)
347
 
                m_scanline_timer->adjust(time_until_pos(0));
348
 
 
349
 
        // create burn-in bitmap
350
 
        if (machine().options().burnin())
351
 
        {
352
 
                int width, height;
353
 
                if (sscanf(machine().options().snap_size(), "%dx%d", &width, &height) != 2 || width == 0 || height == 0)
354
 
                        width = height = 300;
355
 
                m_burnin = auto_alloc(machine(), bitmap_t(width, height, BITMAP_FORMAT_INDEXED64));
356
 
                if (m_burnin == NULL)
357
 
                        fatalerror("Error allocating burn-in bitmap for screen at (%dx%d)\n", width, height);
358
 
                bitmap_fill(m_burnin, NULL, 0);
359
 
        }
360
 
 
361
 
        // load the effect overlay
362
 
        const char *overname = machine().options().effect();
363
 
        if (overname != NULL && strcmp(overname, "none") != 0)
364
 
                load_effect_overlay(overname);
365
 
 
366
 
        // register items for saving
367
 
        save_item(NAME(m_width));
368
 
        save_item(NAME(m_height));
369
 
        save_item(NAME(m_visarea.min_x));
370
 
        save_item(NAME(m_visarea.min_y));
371
 
        save_item(NAME(m_visarea.max_x));
372
 
        save_item(NAME(m_visarea.max_y));
373
 
        save_item(NAME(m_last_partial_scan));
374
 
        save_item(NAME(m_frame_period));
375
 
        save_item(NAME(m_scantime));
376
 
        save_item(NAME(m_pixeltime));
377
 
        save_item(NAME(m_vblank_period));
378
 
        save_item(NAME(m_vblank_start_time));
379
 
        save_item(NAME(m_vblank_end_time));
380
 
        save_item(NAME(m_frame_number));
381
 
}
382
 
 
383
 
 
384
 
//-------------------------------------------------
385
 
//  device_stop - clean up before the machine goes
386
 
//  away
387
 
//-------------------------------------------------
388
 
 
389
 
void screen_device::device_stop()
390
 
{
391
 
        machine().render().texture_free(m_texture[0]);
392
 
        machine().render().texture_free(m_texture[1]);
393
 
        if (m_burnin != NULL)
394
 
                finalize_burnin();
395
 
        global_free(m_screen_overlay_bitmap);
396
 
}
397
 
 
398
 
 
399
 
//-------------------------------------------------
400
 
//  device_post_load - device-specific update
401
 
//  after a save state is loaded
402
 
//-------------------------------------------------
403
 
 
404
 
void screen_device::device_post_load()
405
 
{
406
 
        realloc_screen_bitmaps();
407
 
}
408
 
 
409
 
 
410
 
//-------------------------------------------------
411
 
//  configure - configure screen parameters
412
 
//-------------------------------------------------
413
 
 
414
 
void screen_device::configure(int width, int height, const rectangle &visarea, attoseconds_t frame_period)
415
 
{
416
 
        // validate arguments
417
 
        assert(width > 0);
418
 
        assert(height > 0);
419
 
        assert(visarea.min_x >= 0);
420
 
        assert(visarea.min_y >= 0);
421
 
        assert(m_type == SCREEN_TYPE_VECTOR || visarea.min_x < width);
422
 
        assert(m_type == SCREEN_TYPE_VECTOR || visarea.min_y < height);
423
 
        assert(frame_period > 0);
424
 
 
425
 
        // fill in the new parameters
426
 
        m_width = width;
427
 
        m_height = height;
428
 
        m_visarea = visarea;
429
 
 
430
 
        // reallocate bitmap if necessary
431
 
        realloc_screen_bitmaps();
432
 
 
433
 
        // compute timing parameters
434
 
        m_frame_period = frame_period;
435
 
        m_scantime = frame_period / height;
436
 
        m_pixeltime = frame_period / (height * width);
437
 
 
438
 
        // if there has been no VBLANK time specified in the MACHINE_DRIVER, compute it now
439
 
    // from the visible area, otherwise just used the supplied value
440
 
        if (m_vblank == 0 && !m_oldstyle_vblank_supplied)
441
 
                m_vblank_period = m_scantime * (height - (visarea.max_y + 1 - visarea.min_y));
442
 
        else
443
 
                m_vblank_period = m_vblank;
444
 
 
445
 
        // if we are on scanline 0 already, reset the update timer immediately
446
 
        // otherwise, defer until the next scanline 0
447
 
        if (vpos() == 0)
448
 
                m_scanline0_timer->adjust(attotime::zero);
449
 
        else
450
 
                m_scanline0_timer->adjust(time_until_pos(0));
451
 
 
452
 
        // start the VBLANK timer
453
 
        m_vblank_begin_timer->adjust(time_until_vblank_start());
454
 
 
455
 
        // adjust speed if necessary
456
 
        machine().video().update_refresh_speed();
457
 
}
458
 
 
459
 
 
460
 
//-------------------------------------------------
461
 
//  reset_origin - reset the timing such that the
462
 
//  given (x,y) occurs at the current time
463
 
//-------------------------------------------------
464
 
 
465
 
void screen_device::reset_origin(int beamy, int beamx)
466
 
{
467
 
        // compute the effective VBLANK start/end times
468
 
        attotime curtime = machine().time();
469
 
        m_vblank_end_time = curtime - attotime(0, beamy * m_scantime + beamx * m_pixeltime);
470
 
        m_vblank_start_time = m_vblank_end_time - attotime(0, m_vblank_period);
471
 
 
472
 
        // if we are resetting relative to (0,0) == VBLANK end, call the
473
 
        // scanline 0 timer by hand now; otherwise, adjust it for the future
474
 
        if (beamy == 0 && beamx == 0)
475
 
                scanline0_callback();
476
 
        else
477
 
                m_scanline0_timer->adjust(time_until_pos(0));
478
 
 
479
 
        // if we are resetting relative to (visarea.max_y + 1, 0) == VBLANK start,
480
 
        // call the VBLANK start timer now; otherwise, adjust it for the future
481
 
        if (beamy == m_visarea.max_y + 1 && beamx == 0)
482
 
                vblank_begin_callback();
483
 
        else
484
 
                m_vblank_begin_timer->adjust(time_until_vblank_start());
485
 
}
486
 
 
487
 
 
488
 
//-------------------------------------------------
489
 
//  realloc_screen_bitmaps - reallocate bitmaps
490
 
//  and textures as necessary
491
 
//-------------------------------------------------
492
 
 
493
 
void screen_device::realloc_screen_bitmaps()
494
 
{
495
 
        if (m_type == SCREEN_TYPE_VECTOR)
496
 
                return;
497
 
 
498
 
        int curwidth = 0, curheight = 0;
499
 
 
500
 
        // extract the current width/height from the bitmap
501
 
        if (m_bitmap[0] != NULL)
502
 
        {
503
 
                curwidth = m_bitmap[0]->width;
504
 
                curheight = m_bitmap[0]->height;
505
 
        }
506
 
 
507
 
        // if we're too small to contain this width/height, reallocate our bitmaps and textures
508
 
        if (m_width > curwidth || m_height > curheight)
509
 
        {
510
 
                // free what we have currently
511
 
                machine().render().texture_free(m_texture[0]);
512
 
                machine().render().texture_free(m_texture[1]);
513
 
                auto_free(machine(), m_bitmap[0]);
514
 
                auto_free(machine(), m_bitmap[1]);
515
 
 
516
 
                // compute new width/height
517
 
                curwidth = MAX(m_width, curwidth);
518
 
                curheight = MAX(m_height, curheight);
519
 
 
520
 
                // choose the texture format - convert the screen format to a texture format
521
 
                palette_t *palette = NULL;
522
 
                switch (m_format)
523
 
                {
524
 
                        case BITMAP_FORMAT_INDEXED16:   m_texture_format = TEXFORMAT_PALETTE16; palette = machine().palette;    break;
525
 
                        case BITMAP_FORMAT_RGB15:               m_texture_format = TEXFORMAT_RGB15;             palette = NULL;                         break;
526
 
                        case BITMAP_FORMAT_RGB32:               m_texture_format = TEXFORMAT_RGB32;             palette = NULL;                         break;
527
 
                        default:                                                fatalerror("Invalid bitmap format!");                                                                                           break;
528
 
                }
529
 
 
530
 
                // allocate bitmaps
531
 
                m_bitmap[0] = auto_alloc(machine(), bitmap_t(curwidth, curheight, m_format));
532
 
                bitmap_set_palette(m_bitmap[0], machine().palette);
533
 
                m_bitmap[1] = auto_alloc(machine(), bitmap_t(curwidth, curheight, m_format));
534
 
                bitmap_set_palette(m_bitmap[1], machine().palette);
535
 
 
536
 
                // allocate textures
537
 
                m_texture[0] = machine().render().texture_alloc();
538
 
                m_texture[0]->set_bitmap(m_bitmap[0], &m_visarea, m_texture_format, palette);
539
 
                m_texture[1] = machine().render().texture_alloc();
540
 
                m_texture[1]->set_bitmap(m_bitmap[1], &m_visarea, m_texture_format, palette);
541
 
        }
542
 
}
543
 
 
544
 
 
545
 
//-------------------------------------------------
546
 
//  set_visible_area - just set the visible area
547
 
//-------------------------------------------------
548
 
 
549
 
void screen_device::set_visible_area(int min_x, int max_x, int min_y, int max_y)
550
 
{
551
 
        // validate arguments
552
 
        assert(min_x >= 0);
553
 
        assert(min_y >= 0);
554
 
        assert(min_x < max_x);
555
 
        assert(min_y < max_y);
556
 
 
557
 
        rectangle visarea;
558
 
        visarea.min_x = min_x;
559
 
        visarea.max_x = max_x;
560
 
        visarea.min_y = min_y;
561
 
        visarea.max_y = max_y;
562
 
 
563
 
        configure(m_width, m_height, visarea, m_frame_period);
564
 
}
565
 
 
566
 
 
567
 
//-------------------------------------------------
568
 
//  update_partial - perform a partial update from
569
 
//  the last scanline up to and including the
570
 
//  specified scanline
571
 
//-----------------------------------------------*/
572
 
 
573
 
bool screen_device::update_partial(int scanline)
574
 
{
575
 
        // validate arguments
576
 
        assert(scanline >= 0);
577
 
 
578
 
        LOG_PARTIAL_UPDATES(("Partial: update_partial(%s, %d): ", tag(), scanline));
579
 
 
580
 
        // these two checks only apply if we're allowed to skip frames
581
 
        if (!(machine().config().m_video_attributes & VIDEO_ALWAYS_UPDATE))
582
 
        {
583
 
                // if skipping this frame, bail
584
 
                if (machine().video().skip_this_frame())
585
 
                {
586
 
                        LOG_PARTIAL_UPDATES(("skipped due to frameskipping\n"));
587
 
                        return FALSE;
588
 
                }
589
 
 
590
 
                // skip if this screen is not visible anywhere
591
 
                if (!machine().render().is_live(*this))
592
 
                {
593
 
                        LOG_PARTIAL_UPDATES(("skipped because screen not live\n"));
594
 
                        return FALSE;
595
 
                }
596
 
        }
597
 
 
598
 
        // skip if less than the lowest so far
599
 
        if (scanline < m_last_partial_scan)
600
 
        {
601
 
                LOG_PARTIAL_UPDATES(("skipped because less than previous\n"));
602
 
                return FALSE;
603
 
        }
604
 
 
605
 
        // set the start/end scanlines
606
 
        rectangle clip = m_visarea;
607
 
        if (m_last_partial_scan > clip.min_y)
608
 
                clip.min_y = m_last_partial_scan;
609
 
        if (scanline < clip.max_y)
610
 
                clip.max_y = scanline;
611
 
 
612
 
        // render if necessary
613
 
        bool result = false;
614
 
        if (clip.min_y <= clip.max_y)
615
 
        {
616
 
                UINT32 flags = UPDATE_HAS_NOT_CHANGED;
617
 
 
618
 
                g_profiler.start(PROFILER_VIDEO);
619
 
                LOG_PARTIAL_UPDATES(("updating %d-%d\n", clip.min_y, clip.max_y));
620
 
 
621
 
                flags = screen_update(*m_bitmap[m_curbitmap], clip);
622
 
                m_partial_updates_this_frame++;
623
 
                g_profiler.stop();
624
 
 
625
 
                // if we modified the bitmap, we have to commit
626
 
                m_changed |= ~flags & UPDATE_HAS_NOT_CHANGED;
627
 
                result = true;
628
 
        }
629
 
 
630
 
        // remember where we left off
631
 
        m_last_partial_scan = scanline + 1;
632
 
        return result;
633
 
}
634
 
 
635
 
 
636
 
//-------------------------------------------------
637
 
//  update_now - perform an update from the last
638
 
//  beam position up to the current beam position
639
 
//-------------------------------------------------
640
 
 
641
 
void screen_device::update_now()
642
 
{
643
 
        int current_vpos = vpos();
644
 
        int current_hpos = hpos();
645
 
 
646
 
        // since we can currently update only at the scanline
647
 
    // level, we are trying to do the right thing by
648
 
    // updating including the current scanline, only if the
649
 
    // beam is past the halfway point horizontally.
650
 
    // If the beam is in the first half of the scanline,
651
 
    // we only update up to the previous scanline.
652
 
    // This minimizes the number of pixels that might be drawn
653
 
    // incorrectly until we support a pixel level granularity
654
 
        if (current_hpos < (m_width / 2) && current_vpos > 0)
655
 
                current_vpos = current_vpos - 1;
656
 
 
657
 
        update_partial(current_vpos);
658
 
}
659
 
 
660
 
 
661
 
//-------------------------------------------------
662
 
//  vpos - returns the current vertical position
663
 
//  of the beam
664
 
//-------------------------------------------------
665
 
 
666
 
int screen_device::vpos() const
667
 
{
668
 
        attoseconds_t delta = (machine().time() - m_vblank_start_time).as_attoseconds();
669
 
        int vpos;
670
 
 
671
 
        // round to the nearest pixel
672
 
        delta += m_pixeltime / 2;
673
 
 
674
 
        // compute the v position relative to the start of VBLANK
675
 
        vpos = delta / m_scantime;
676
 
 
677
 
        // adjust for the fact that VBLANK starts at the bottom of the visible area
678
 
        return (m_visarea.max_y + 1 + vpos) % m_height;
679
 
}
680
 
 
681
 
 
682
 
//-------------------------------------------------
683
 
//  hpos - returns the current horizontal position
684
 
//  of the beam
685
 
//-------------------------------------------------
686
 
 
687
 
int screen_device::hpos() const
688
 
{
689
 
        attoseconds_t delta = (machine().time() - m_vblank_start_time).as_attoseconds();
690
 
 
691
 
        // round to the nearest pixel
692
 
        delta += m_pixeltime / 2;
693
 
 
694
 
        // compute the v position relative to the start of VBLANK
695
 
        int vpos = delta / m_scantime;
696
 
 
697
 
        // subtract that from the total time
698
 
        delta -= vpos * m_scantime;
699
 
 
700
 
        // return the pixel offset from the start of this scanline
701
 
        return delta / m_pixeltime;
702
 
}
703
 
 
704
 
 
705
 
//-------------------------------------------------
706
 
//  time_until_pos - returns the amount of time
707
 
//  remaining until the beam is at the given
708
 
//  hpos,vpos
709
 
//-------------------------------------------------
710
 
 
711
 
attotime screen_device::time_until_pos(int vpos, int hpos) const
712
 
{
713
 
        // validate arguments
714
 
        assert(vpos >= 0);
715
 
        assert(hpos >= 0);
716
 
 
717
 
        // since we measure time relative to VBLANK, compute the scanline offset from VBLANK
718
 
        vpos += m_height - (m_visarea.max_y + 1);
719
 
        vpos %= m_height;
720
 
 
721
 
        // compute the delta for the given X,Y position
722
 
        attoseconds_t targetdelta = (attoseconds_t)vpos * m_scantime + (attoseconds_t)hpos * m_pixeltime;
723
 
 
724
 
        // if we're past that time (within 1/2 of a pixel), head to the next frame
725
 
        attoseconds_t curdelta = (machine().time() - m_vblank_start_time).as_attoseconds();
726
 
        if (targetdelta <= curdelta + m_pixeltime / 2)
727
 
                targetdelta += m_frame_period;
728
 
        while (targetdelta <= curdelta)
729
 
                targetdelta += m_frame_period;
730
 
 
731
 
        // return the difference
732
 
        return attotime(0, targetdelta - curdelta);
733
 
}
734
 
 
735
 
 
736
 
//-------------------------------------------------
737
 
//  time_until_vblank_end - returns the amount of
738
 
//  time remaining until the end of the current
739
 
//  VBLANK (if in progress) or the end of the next
740
 
//  VBLANK
741
 
//-------------------------------------------------
742
 
 
743
 
attotime screen_device::time_until_vblank_end() const
744
 
{
745
 
        // if we are in the VBLANK region, compute the time until the end of the current VBLANK period
746
 
        attotime target_time = m_vblank_end_time;
747
 
        if (!vblank())
748
 
                target_time += attotime(0, m_frame_period);
749
 
        return target_time - machine().time();
750
 
}
751
 
 
752
 
 
753
 
//-------------------------------------------------
754
 
//  register_vblank_callback - registers a VBLANK
755
 
//  callback
756
 
//-------------------------------------------------
757
 
 
758
 
void screen_device::register_vblank_callback(vblank_state_delegate vblank_callback)
759
 
{
760
 
        // validate arguments
761
 
        assert(!vblank_callback.isnull());
762
 
 
763
 
        // check if we already have this callback registered
764
 
        callback_item *item;
765
 
        for (item = m_callback_list.first(); item != NULL; item = item->next())
766
 
                if (item->m_callback == vblank_callback)
767
 
                        break;
768
 
 
769
 
        // if not found, register
770
 
        if (item == NULL)
771
 
                m_callback_list.append(*global_alloc(callback_item(vblank_callback)));
772
 
}
773
 
 
774
 
 
775
 
//-------------------------------------------------
776
 
//  vblank_begin_callback - call any external
777
 
//  callbacks to signal the VBLANK period has begun
778
 
//-------------------------------------------------
779
 
 
780
 
void screen_device::vblank_begin_callback()
781
 
{
782
 
        // reset the starting VBLANK time
783
 
        m_vblank_start_time = machine().time();
784
 
        m_vblank_end_time = m_vblank_start_time + attotime(0, m_vblank_period);
785
 
 
786
 
        // call the screen specific callbacks
787
 
        for (callback_item *item = m_callback_list.first(); item != NULL; item = item->next())
788
 
                item->m_callback(*this, true);
789
 
 
790
 
        // if this is the primary screen and we need to update now
791
 
        if (this == machine().primary_screen && !(machine().config().m_video_attributes & VIDEO_UPDATE_AFTER_VBLANK))
792
 
                machine().video().frame_update();
793
 
 
794
 
        // reset the VBLANK start timer for the next frame
795
 
        m_vblank_begin_timer->adjust(time_until_vblank_start());
796
 
 
797
 
        // if no VBLANK period, call the VBLANK end callback immedietely, otherwise reset the timer
798
 
        if (m_vblank_period == 0)
799
 
                vblank_end_callback();
800
 
        else
801
 
                m_vblank_end_timer->adjust(time_until_vblank_end());
802
 
}
803
 
 
804
 
 
805
 
//-------------------------------------------------
806
 
//  vblank_end_callback - call any external
807
 
//  callbacks to signal the VBLANK period has ended
808
 
//-------------------------------------------------
809
 
 
810
 
void screen_device::vblank_end_callback()
811
 
{
812
 
        // call the screen specific callbacks
813
 
        for (callback_item *item = m_callback_list.first(); item != NULL; item = item->next())
814
 
                item->m_callback(*this, false);
815
 
 
816
 
        // if this is the primary screen and we need to update now
817
 
        if (this == machine().primary_screen && (machine().config().m_video_attributes & VIDEO_UPDATE_AFTER_VBLANK))
818
 
                machine().video().frame_update();
819
 
 
820
 
        // increment the frame number counter
821
 
        m_frame_number++;
822
 
}
823
 
 
824
 
 
825
 
//-------------------------------------------------
826
 
//  scanline0_callback - reset partial updates
827
 
//  for a screen
828
 
//-------------------------------------------------
829
 
 
830
 
void screen_device::scanline0_callback()
831
 
{
832
 
        // reset partial updates
833
 
        m_last_partial_scan = 0;
834
 
        m_partial_updates_this_frame = 0;
835
 
 
836
 
        m_scanline0_timer->adjust(time_until_pos(0));
837
 
}
838
 
 
839
 
 
840
 
//-------------------------------------------------
841
 
//  scanline_update_callback - perform partial
842
 
//  updates on each scanline
843
 
//-------------------------------------------------
844
 
 
845
 
void screen_device::scanline_update_callback(int scanline)
846
 
{
847
 
        // force a partial update to the current scanline
848
 
        update_partial(scanline);
849
 
 
850
 
        // compute the next visible scanline
851
 
        scanline++;
852
 
        if (scanline > m_visarea.max_y)
853
 
                scanline = m_visarea.min_y;
854
 
        m_scanline_timer->adjust(time_until_pos(scanline), scanline);
855
 
}
856
 
 
857
 
 
858
 
//-------------------------------------------------
859
 
//  update_quads - set up the quads for this
860
 
//  screen
861
 
//-------------------------------------------------
862
 
 
863
 
bool screen_device::update_quads()
864
 
{
865
 
        // only update if live
866
 
        if (machine().render().is_live(*this))
867
 
        {
868
 
                // only update if empty and not a vector game; otherwise assume the driver did it directly
869
 
                if (m_type != SCREEN_TYPE_VECTOR && (machine().config().m_video_attributes & VIDEO_SELF_RENDER) == 0)
870
 
                {
871
 
                        // if we're not skipping the frame and if the screen actually changed, then update the texture
872
 
                        if (!machine().video().skip_this_frame() && m_changed)
873
 
                        {
874
 
                                rectangle fixedvis = m_visarea;
875
 
                                fixedvis.max_x++;
876
 
                                fixedvis.max_y++;
877
 
 
878
 
                                palette_t *palette = (m_texture_format == TEXFORMAT_PALETTE16) ? machine().palette : NULL;
879
 
                                m_texture[m_curbitmap]->set_bitmap(m_bitmap[m_curbitmap], &fixedvis, m_texture_format, palette);
880
 
 
881
 
                                m_curtexture = m_curbitmap;
882
 
                                m_curbitmap = 1 - m_curbitmap;
883
 
                        }
884
 
 
885
 
                        // create an empty container with a single quad
886
 
                        m_container->empty();
887
 
                        m_container->add_quad(0.0f, 0.0f, 1.0f, 1.0f, MAKE_ARGB(0xff,0xff,0xff,0xff), m_texture[m_curtexture], PRIMFLAG_BLENDMODE(BLENDMODE_NONE) | PRIMFLAG_SCREENTEX(1));
888
 
                }
889
 
        }
890
 
 
891
 
        // reset the screen changed flags
892
 
        bool result = m_changed;
893
 
        m_changed = false;
894
 
        return result;
895
 
}
896
 
 
897
 
 
898
 
//-------------------------------------------------
899
 
//  update_burnin - update the burnin bitmap
900
 
//-------------------------------------------------
901
 
 
902
 
void screen_device::update_burnin()
903
 
{
904
 
#undef rand
905
 
        if (m_burnin == NULL)
906
 
                return;
907
 
 
908
 
        bitmap_t *srcbitmap = m_bitmap[m_curtexture];
909
 
        if (srcbitmap == NULL)
910
 
                return;
911
 
 
912
 
        int srcwidth = srcbitmap->width;
913
 
        int srcheight = srcbitmap->height;
914
 
        int dstwidth = m_burnin->width;
915
 
        int dstheight = m_burnin->height;
916
 
        int xstep = (srcwidth << 16) / dstwidth;
917
 
        int ystep = (srcheight << 16) / dstheight;
918
 
        int xstart = ((UINT32)rand() % 32767) * xstep / 32767;
919
 
        int ystart = ((UINT32)rand() % 32767) * ystep / 32767;
920
 
        int srcx, srcy;
921
 
        int x, y;
922
 
 
923
 
        // iterate over rows in the destination
924
 
        for (y = 0, srcy = ystart; y < dstheight; y++, srcy += ystep)
925
 
        {
926
 
                UINT64 *dst = BITMAP_ADDR64(m_burnin, y, 0);
927
 
 
928
 
                // handle the 16-bit palettized case
929
 
                if (srcbitmap->format == BITMAP_FORMAT_INDEXED16)
930
 
                {
931
 
                        const UINT16 *src = BITMAP_ADDR16(srcbitmap, srcy >> 16, 0);
932
 
                        const rgb_t *palette = palette_entry_list_adjusted(machine().palette);
933
 
                        for (x = 0, srcx = xstart; x < dstwidth; x++, srcx += xstep)
934
 
                        {
935
 
                                rgb_t pixel = palette[src[srcx >> 16]];
936
 
                                dst[x] += RGB_GREEN(pixel) + RGB_RED(pixel) + RGB_BLUE(pixel);
937
 
                        }
938
 
                }
939
 
 
940
 
                // handle the 15-bit RGB case
941
 
                else if (srcbitmap->format == BITMAP_FORMAT_RGB15)
942
 
                {
943
 
                        const UINT16 *src = BITMAP_ADDR16(srcbitmap, srcy >> 16, 0);
944
 
                        for (x = 0, srcx = xstart; x < dstwidth; x++, srcx += xstep)
945
 
                        {
946
 
                                rgb15_t pixel = src[srcx >> 16];
947
 
                                dst[x] += ((pixel >> 10) & 0x1f) + ((pixel >> 5) & 0x1f) + ((pixel >> 0) & 0x1f);
948
 
                        }
949
 
                }
950
 
 
951
 
                // handle the 32-bit RGB case
952
 
                else if (srcbitmap->format == BITMAP_FORMAT_RGB32)
953
 
                {
954
 
                        const UINT32 *src = BITMAP_ADDR32(srcbitmap, srcy >> 16, 0);
955
 
                        for (x = 0, srcx = xstart; x < dstwidth; x++, srcx += xstep)
956
 
                        {
957
 
                                rgb_t pixel = src[srcx >> 16];
958
 
                                dst[x] += RGB_GREEN(pixel) + RGB_RED(pixel) + RGB_BLUE(pixel);
959
 
                        }
960
 
                }
961
 
        }
962
 
}
963
 
 
964
 
 
965
 
//-------------------------------------------------
966
 
//  finalize_burnin - finalize the burnin bitmap
967
 
//-------------------------------------------------
968
 
 
969
 
void screen_device::finalize_burnin()
970
 
{
971
 
        if (m_burnin == NULL)
972
 
                return;
973
 
 
974
 
        // compute the scaled visible region
975
 
        rectangle scaledvis;
976
 
        scaledvis.min_x = m_visarea.min_x * m_burnin->width / m_width;
977
 
        scaledvis.max_x = m_visarea.max_x * m_burnin->width / m_width;
978
 
        scaledvis.min_y = m_visarea.min_y * m_burnin->height / m_height;
979
 
        scaledvis.max_y = m_visarea.max_y * m_burnin->height / m_height;
980
 
 
981
 
        // wrap a bitmap around the subregion we care about
982
 
        bitmap_t *finalmap = auto_alloc(machine(), bitmap_t(scaledvis.max_x + 1 - scaledvis.min_x,
983
 
                                                        scaledvis.max_y + 1 - scaledvis.min_y,
984
 
                                                        BITMAP_FORMAT_ARGB32));
985
 
 
986
 
        int srcwidth = m_burnin->width;
987
 
        int srcheight = m_burnin->height;
988
 
        int dstwidth = finalmap->width;
989
 
        int dstheight = finalmap->height;
990
 
        int xstep = (srcwidth << 16) / dstwidth;
991
 
        int ystep = (srcheight << 16) / dstheight;
992
 
 
993
 
        // find the maximum value
994
 
        UINT64 minval = ~(UINT64)0;
995
 
        UINT64 maxval = 0;
996
 
        for (int y = 0; y < srcheight; y++)
997
 
        {
998
 
                UINT64 *src = BITMAP_ADDR64(m_burnin, y, 0);
999
 
                for (int x = 0; x < srcwidth; x++)
1000
 
                {
1001
 
                        minval = MIN(minval, src[x]);
1002
 
                        maxval = MAX(maxval, src[x]);
1003
 
                }
1004
 
        }
1005
 
 
1006
 
        if (minval == maxval)
1007
 
                return;
1008
 
 
1009
 
        // now normalize and convert to RGB
1010
 
        for (int y = 0, srcy = 0; y < dstheight; y++, srcy += ystep)
1011
 
        {
1012
 
                UINT64 *src = BITMAP_ADDR64(m_burnin, srcy >> 16, 0);
1013
 
                UINT32 *dst = BITMAP_ADDR32(finalmap, y, 0);
1014
 
                for (int x = 0, srcx = 0; x < dstwidth; x++, srcx += xstep)
1015
 
                {
1016
 
                        int brightness = (UINT64)(maxval - src[srcx >> 16]) * 255 / (maxval - minval);
1017
 
                        dst[x] = MAKE_ARGB(0xff, brightness, brightness, brightness);
1018
 
                }
1019
 
        }
1020
 
 
1021
 
        // write the final PNG
1022
 
 
1023
 
        // compute the name and create the file
1024
 
        emu_file file(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
1025
 
        file_error filerr = file.open(machine().basename(), PATH_SEPARATOR "burnin-", tag(), ".png") ;
1026
 
        if (filerr == FILERR_NONE)
1027
 
        {
1028
 
                png_info pnginfo = { 0 };
1029
 
//      png_error pngerr;
1030
 
                char text[256];
1031
 
 
1032
 
                // add two text entries describing the image
1033
 
                sprintf(text, APPNAME " %s", build_version);
1034
 
                png_add_text(&pnginfo, "Software", text);
1035
 
                sprintf(text, "%s %s", machine().system().manufacturer, machine().system().description);
1036
 
                png_add_text(&pnginfo, "System", text);
1037
 
 
1038
 
                // now do the actual work
1039
 
                png_write_bitmap(file, &pnginfo, finalmap, 0, NULL);
1040
 
 
1041
 
                // free any data allocated
1042
 
                png_free(&pnginfo);
1043
 
        }
1044
 
}
1045
 
 
1046
 
 
1047
 
//-------------------------------------------------
1048
 
//  finalize_burnin - finalize the burnin bitmap
1049
 
//-------------------------------------------------
1050
 
 
1051
 
void screen_device::load_effect_overlay(const char *filename)
1052
 
{
1053
 
        // ensure that there is a .png extension
1054
 
        astring fullname(filename);
1055
 
        int extension = fullname.rchr(0, '.');
1056
 
        if (extension != -1)
1057
 
                fullname.del(extension, -1);
1058
 
        fullname.cat(".png");
1059
 
 
1060
 
        // load the file
1061
 
        emu_file file(machine().options().art_path(), OPEN_FLAG_READ);
1062
 
        m_screen_overlay_bitmap = render_load_png(file, NULL, fullname, NULL, NULL);
1063
 
        if (m_screen_overlay_bitmap != NULL)
1064
 
                m_container->set_overlay(m_screen_overlay_bitmap);
1065
 
        else
1066
 
                mame_printf_warning("Unable to load effect PNG file '%s'\n", fullname.cstr());
1067
 
}
1068
 
 
1069
 
//-------------------------------------------------
1070
 
//  screen_update - default implementation which
1071
 
//  calls to the legacy screen_update function
1072
 
//-------------------------------------------------
1073
 
 
1074
 
bool screen_device::screen_update(bitmap_t &bitmap, const rectangle &cliprect)
1075
 
{
1076
 
        if (m_screen_update != NULL) {
1077
 
                return (*m_screen_update)(this, &bitmap, &cliprect);
1078
 
        } else {
1079
 
                machine().driver_data<driver_device>()->screen_update(*this, bitmap, cliprect);
1080
 
        }
1081
 
        return 0;
1082
 
}
1083
 
 
1084
 
//-------------------------------------------------
1085
 
//  screen_eof - default implementation which
1086
 
//  calls to the legacy screen_update function
1087
 
//-------------------------------------------------
1088
 
 
1089
 
void screen_device::screen_eof()
1090
 
{
1091
 
        if (m_screen_eof != NULL) {
1092
 
                return (*m_screen_eof)(this, machine());
1093
 
        } else {
1094
 
                machine().driver_data<driver_device>()->screen_eof();
1095
 
        }
1096
 
}