1 |
|
/* |
2 |
|
* video.cpp - Video/graphics emulation |
3 |
|
* |
4 |
< |
* SheepShaver (C) 1997-2004 Marc Hellwig and Christian Bauer |
4 |
> |
* SheepShaver (C) 1997-2005 Marc Hellwig and Christian Bauer |
5 |
|
* |
6 |
|
* This program is free software; you can redistribute it and/or modify |
7 |
|
* it under the terms of the GNU General Public License as published by |
74 |
|
// Function pointers of imported functions |
75 |
|
typedef int16 (*iocic_ptr)(void *, int16); |
76 |
|
static uint32 iocic_tvect = 0; |
77 |
< |
static inline int16 IOCommandIsComplete(void *arg1, int16 arg2) |
77 |
> |
static inline int16 IOCommandIsComplete(uintptr arg1, int16 arg2) |
78 |
|
{ |
79 |
< |
return (int16)CallMacOS2(iocic_ptr, iocic_tvect, arg1, arg2); |
79 |
> |
return (int16)CallMacOS2(iocic_ptr, iocic_tvect, (void *)arg1, arg2); |
80 |
|
} |
81 |
|
typedef int16 (*vslnewis_ptr)(void *, uint32, uint32 *); |
82 |
|
static uint32 vslnewis_tvect = 0; |
83 |
< |
static inline int16 VSLNewInterruptService(void *arg1, uint32 arg2, uint32 *arg3) |
83 |
> |
static inline int16 VSLNewInterruptService(uintptr arg1, uint32 arg2, uintptr arg3) |
84 |
|
{ |
85 |
< |
return (int16)CallMacOS3(vslnewis_ptr, vslnewis_tvect, arg1, arg2, arg3); |
85 |
> |
return (int16)CallMacOS3(vslnewis_ptr, vslnewis_tvect, (void *)arg1, arg2, (uint32 *)arg3); |
86 |
|
} |
87 |
|
typedef int16 (*vsldisposeis_ptr)(uint32); |
88 |
|
static uint32 vsldisposeis_tvect = 0; |
98 |
|
} |
99 |
|
typedef void (*nqdmisc_ptr)(uint32, void *); |
100 |
|
static uint32 nqdmisc_tvect = 0; |
101 |
< |
void NQDMisc(uint32 arg1, void *arg2) |
101 |
> |
void NQDMisc(uint32 arg1, uintptr arg2) |
102 |
|
{ |
103 |
< |
CallMacOS2(nqdmisc_ptr, nqdmisc_tvect, arg1, arg2); |
103 |
> |
CallMacOS2(nqdmisc_ptr, nqdmisc_tvect, arg1, (void *)arg2); |
104 |
|
} |
105 |
|
|
106 |
|
|
156 |
|
csSave->saveMode = VModes[cur_mode].viAppleMode; |
157 |
|
csSave->savePage = 0; |
158 |
|
csSave->saveVidParms = 0; // Add the right table |
159 |
– |
csSave->gammaTable = NULL; // No gamma table yet |
160 |
– |
csSave->maxGammaTableSize = 0; |
159 |
|
csSave->luminanceMapping = false; |
160 |
|
csSave->cursorX = 0; |
161 |
|
csSave->cursorY = 0; |
162 |
|
csSave->cursorVisible = 0; |
163 |
|
csSave->cursorSet = 0; |
164 |
|
|
165 |
< |
// Activate default gamma table |
165 |
> |
// Find and set default gamma table |
166 |
> |
csSave->gammaTable = 0; |
167 |
> |
csSave->maxGammaTableSize = 0; |
168 |
|
set_gamma(csSave, 0); |
169 |
|
|
170 |
|
// Install and activate interrupt service |
171 |
|
SheepVar32 theServiceID = 0; |
172 |
< |
VSLNewInterruptService(csSave->regEntryID, FOURCC('v','b','l',' '), (uint32 *)theServiceID.addr()); |
172 |
> |
VSLNewInterruptService(csSave->regEntryID, FOURCC('v','b','l',' '), theServiceID.addr()); |
173 |
|
csSave->vslServiceID = theServiceID.value(); |
174 |
|
D(bug(" Interrupt ServiceID %08lx\n", csSave->vslServiceID)); |
175 |
|
csSave->interruptsEnabled = true; |
182 |
|
* Video driver control routine |
183 |
|
*/ |
184 |
|
|
185 |
+ |
static bool allocate_gamma_table(VidLocals *csSave, uint32 size) |
186 |
+ |
{ |
187 |
+ |
if (size > csSave->maxGammaTableSize) { |
188 |
+ |
if (csSave->gammaTable) { |
189 |
+ |
Mac_sysfree(csSave->gammaTable); |
190 |
+ |
csSave->gammaTable = 0; |
191 |
+ |
csSave->maxGammaTableSize = 0; |
192 |
+ |
} |
193 |
+ |
if ((csSave->gammaTable = Mac_sysalloc(size)) == 0) |
194 |
+ |
return false; |
195 |
+ |
csSave->maxGammaTableSize = size; |
196 |
+ |
} |
197 |
+ |
return true; |
198 |
+ |
} |
199 |
+ |
|
200 |
|
static int16 set_gamma(VidLocals *csSave, uint32 gamma) |
201 |
|
{ |
202 |
< |
GammaTbl *clientGamma = (GammaTbl *)gamma; |
188 |
< |
GammaTbl *gammaTable = csSave->gammaTable; |
202 |
> |
return paramErr; |
203 |
|
|
204 |
< |
if (clientGamma == NULL) { |
204 |
> |
if (gamma == 0) { // Build linear ramp, 256 entries |
205 |
|
|
206 |
< |
// No gamma table supplied, build linear ramp |
207 |
< |
uint32 linearRampSize = sizeof(GammaTbl) + 256 - 2; |
208 |
< |
uint8 *correctionData; |
209 |
< |
|
210 |
< |
// Allocate new gamma table if existing gamma table is smaller than required. |
211 |
< |
if (linearRampSize > csSave->maxGammaTableSize) { |
212 |
< |
delete[] csSave->gammaTable; |
213 |
< |
csSave->gammaTable = (GammaTbl *)new uint8[linearRampSize]; |
214 |
< |
csSave->maxGammaTableSize = linearRampSize; |
215 |
< |
gammaTable = csSave->gammaTable; |
216 |
< |
} |
203 |
< |
|
204 |
< |
gammaTable->gVersion = 0; // A version 0 style of the GammaTbl structure |
205 |
< |
gammaTable->gType = 0; // Frame buffer hardware invariant |
206 |
< |
gammaTable->gFormulaSize = 0; // No formula data, just correction data |
207 |
< |
gammaTable->gChanCnt = 1; // Apply same correction to Red, Green, & Blue |
208 |
< |
gammaTable->gDataCnt = 256; // gDataCnt == 2^^gDataWidth |
209 |
< |
gammaTable->gDataWidth = 8; // 8 bits of significant data per entry |
210 |
< |
|
211 |
< |
// Find the starting address of the correction data. This can be computed by starting at |
212 |
< |
// the address of gFormula[0] and adding the gFormulaSize. |
213 |
< |
correctionData = (uint8 *)((uint32)&gammaTable->gFormulaData[0] + gammaTable->gFormulaSize); |
206 |
> |
// Allocate new table, if necessary |
207 |
> |
if (!allocate_gamma_table(csSave, SIZEOF_GammaTbl + 256)) |
208 |
> |
return memFullErr; |
209 |
> |
|
210 |
> |
// Initialize header |
211 |
> |
WriteMacInt16(csSave->gammaTable + gVersion, 0); // A version 0 style of the GammaTbl structure |
212 |
> |
WriteMacInt16(csSave->gammaTable + gType, 0); // Frame buffer hardware invariant |
213 |
> |
WriteMacInt16(csSave->gammaTable + gFormulaSize, 0); // No formula data, just correction data |
214 |
> |
WriteMacInt16(csSave->gammaTable + gChanCnt, 1); // Apply same correction to Red, Green, & Blue |
215 |
> |
WriteMacInt16(csSave->gammaTable + gDataCnt, 256); // gDataCnt == 2^^gDataWidth |
216 |
> |
WriteMacInt16(csSave->gammaTable + gDataWidth, 8); // 8 bits of significant data per entry |
217 |
|
|
218 |
|
// Build the linear ramp |
219 |
< |
for (int i=0; i<gammaTable->gDataCnt; i++) |
220 |
< |
*correctionData++ = i; |
219 |
> |
uint32 p = csSave->gammaTable + gFormulaData; |
220 |
> |
for (int i=0; i<256; i++) |
221 |
> |
WriteMacInt8(p + i, i); |
222 |
|
|
223 |
< |
} else { |
223 |
> |
} else { // User-supplied gamma table |
224 |
|
|
225 |
< |
// User supplied a gamma table, so make sure it is a valid one |
226 |
< |
if (clientGamma->gVersion != 0) |
225 |
> |
// Validate header |
226 |
> |
if (ReadMacInt16(gamma + gVersion) != 0) |
227 |
|
return paramErr; |
228 |
< |
if (clientGamma->gType != 0) |
228 |
> |
if (ReadMacInt16(gamma + gType) != 0) |
229 |
|
return paramErr; |
230 |
< |
if ((clientGamma->gChanCnt != 1) && (clientGamma->gChanCnt != 3)) |
230 |
> |
int chan_cnt = ReadMacInt16(gamma + gChanCnt); |
231 |
> |
if (chan_cnt != 1 && chan_cnt != 3) |
232 |
|
return paramErr; |
233 |
< |
if (clientGamma->gDataWidth > 8) |
233 |
> |
int data_width = ReadMacInt16(gamma + gDataWidth); |
234 |
> |
if (data_width > 8) |
235 |
|
return paramErr; |
236 |
< |
if (clientGamma->gDataCnt != (1 << clientGamma->gDataWidth)) |
236 |
> |
int data_cnt = ReadMacInt16(gamma + gDataWidth); |
237 |
> |
if (data_cnt != (1 << data_width)) |
238 |
|
return paramErr; |
239 |
|
|
240 |
< |
uint32 tableSize = sizeof(GammaTbl) // fixed size header |
241 |
< |
+ clientGamma->gFormulaSize // add formula size |
242 |
< |
+ clientGamma->gChanCnt * clientGamma->gDataCnt // assume 1 byte/entry |
243 |
< |
- 2; // correct gFormulaData[0] counted twice |
237 |
< |
|
238 |
< |
// Allocate new gamma table if existing gamma table is smaller than required. |
239 |
< |
if (tableSize > csSave->maxGammaTableSize) { |
240 |
< |
delete[] csSave->gammaTable; |
241 |
< |
csSave->gammaTable = (GammaTbl *)new uint8[tableSize]; |
242 |
< |
csSave->maxGammaTableSize = tableSize; |
243 |
< |
gammaTable = csSave->gammaTable; |
244 |
< |
} |
240 |
> |
// Allocate new table, if necessary |
241 |
> |
int size = SIZEOF_GammaTbl + ReadMacInt16(gamma + gFormulaSize) + chan_cnt * data_cnt; |
242 |
> |
if (!allocate_gamma_table(csSave, size)) |
243 |
> |
return memFullErr; |
244 |
|
|
245 |
< |
// Copy gamma table header |
246 |
< |
*gammaTable = *clientGamma; |
248 |
< |
|
249 |
< |
// Copy the formula data (if any) |
250 |
< |
uint8 *newData = (uint8 *)&gammaTable->gFormulaData[0]; // Point to newGamma's formula data |
251 |
< |
uint8 *clientData = (uint8 *)&clientGamma->gFormulaData[0]; // Point to clientGamma's formula data |
252 |
< |
for (int i=0; i<gammaTable->gFormulaSize; i++) |
253 |
< |
*newData++ = *clientData++; |
254 |
< |
|
255 |
< |
// Copy the correction data. Convientiently, after copying the formula data, the 'newData' |
256 |
< |
// pointer and the 'clientData' pointer are pointing to the their respective starting points |
257 |
< |
// of their correction data. |
258 |
< |
for (int i=0; i<gammaTable->gChanCnt; i++) |
259 |
< |
for (int j=0; j<gammaTable->gDataCnt; j++) |
260 |
< |
*newData++ = *clientData++; |
245 |
> |
// Copy table |
246 |
> |
Mac2Mac_memcpy(csSave->gammaTable, gamma, size); |
247 |
|
} |
248 |
|
return noErr; |
249 |
|
} |
284 |
|
uint8 *green_gamma = NULL; |
285 |
|
uint8 *blue_gamma = NULL; |
286 |
|
int gamma_data_width = 0; |
287 |
< |
if (display_type == DIS_SCREEN && csSave->gammaTable != NULL) { // Windows are gamma-corrected by BeOS |
288 |
< |
do_gamma = true; |
289 |
< |
GammaTbl *gamma = csSave->gammaTable; |
290 |
< |
gamma_data_width = gamma->gDataWidth; |
291 |
< |
red_gamma = (uint8 *)&gamma->gFormulaData + gamma->gFormulaSize; |
292 |
< |
if (gamma->gChanCnt == 1) { |
293 |
< |
green_gamma = blue_gamma = red_gamma; |
294 |
< |
} else { |
295 |
< |
green_gamma = red_gamma + gamma->gDataCnt; |
296 |
< |
blue_gamma = red_gamma + 2 * gamma->gDataCnt; |
287 |
> |
if (csSave->gammaTable) { |
288 |
> |
#ifdef __BEOS__ |
289 |
> |
// Windows are gamma-corrected by BeOS |
290 |
> |
const bool can_do_gamma = (display_type == DIS_SCREEN); |
291 |
> |
#else |
292 |
> |
const bool can_do_gamma = true; |
293 |
> |
#endif |
294 |
> |
if (can_do_gamma) { |
295 |
> |
uint32 gamma_table = csSave->gammaTable; |
296 |
> |
red_gamma = Mac2HostAddr(gamma_table + gFormulaData + ReadMacInt16(gamma_table + gFormulaSize)); |
297 |
> |
int chan_cnt = ReadMacInt16(gamma_table + gChanCnt); |
298 |
> |
if (chan_cnt == 1) |
299 |
> |
green_gamma = blue_gamma = red_gamma; |
300 |
> |
else { |
301 |
> |
int ofs = ReadMacInt16(gamma_table + gDataCnt); |
302 |
> |
green_gamma = red_gamma + ofs; |
303 |
> |
blue_gamma = green_gamma + ofs; |
304 |
> |
} |
305 |
> |
gamma_data_width = ReadMacInt16(gamma_table + gDataWidth); |
306 |
> |
do_gamma = true; |
307 |
|
} |
308 |
|
} |
309 |
|
|
351 |
|
return noErr; |
352 |
|
} |
353 |
|
|
354 |
< |
case cscSetGamma: // SetGamma |
355 |
< |
D(bug("SetGamma\n")); |
356 |
< |
return set_gamma(csSave, ReadMacInt32(param)); |
354 |
> |
case cscSetGamma: { // SetGamma |
355 |
> |
uint32 user_table = ReadMacInt32(param + csGTable); |
356 |
> |
D(bug("SetGamma %08x\n", user_table)); |
357 |
> |
return set_gamma(csSave, ReadMacInt32(user_table)); |
358 |
> |
} |
359 |
|
|
360 |
|
case cscGrayPage: { // GrayPage |
361 |
|
D(bug("GrayPage %d\n", ReadMacInt16(param + csPage))); |
446 |
|
MacCursor[3] = ReadMacInt8(0x887); |
447 |
|
|
448 |
|
// Set new cursor image |
449 |
< |
if (display_type == DIS_SCREEN) |
449 |
> |
if (!video_can_change_cursor()) |
450 |
|
return controlErr; |
451 |
|
if (changed) |
452 |
|
video_set_cursor(); |
688 |
|
WriteMacInt32(param + csVerticalLines, 768); |
689 |
|
WriteMacInt32(param + csRefreshRate, 75<<16); |
690 |
|
break; |
691 |
+ |
case APPLE_1152x768: |
692 |
+ |
WriteMacInt32(param + csHorizontalPixels, 1152); |
693 |
+ |
WriteMacInt32(param + csVerticalLines, 768); |
694 |
+ |
WriteMacInt32(param + csRefreshRate, 75<<16); |
695 |
+ |
break; |
696 |
|
case APPLE_1152x900: |
697 |
|
WriteMacInt32(param + csHorizontalPixels, 1152); |
698 |
|
WriteMacInt32(param + csVerticalLines, 900); |
811 |
|
case APPLE_1024x768: |
812 |
|
timing = timingVESA_1024x768_75hz; |
813 |
|
break; |
814 |
+ |
case APPLE_1152x768: |
815 |
+ |
timing = timingApple_1152x870_75hz; // FIXME |
816 |
+ |
break; |
817 |
|
case APPLE_1152x900: |
818 |
|
timing = timingApple_1152x870_75hz; |
819 |
|
break; |
874 |
|
* Native (PCI) driver entry |
875 |
|
*/ |
876 |
|
|
877 |
< |
int16 VideoDoDriverIO(void *spaceID, void *commandID, void *commandContents, uint32 commandCode, uint32 commandKind) |
877 |
> |
int16 VideoDoDriverIO(uint32 spaceID, uint32 commandID, uint32 commandContents, uint32 commandCode, uint32 commandKind) |
878 |
|
{ |
879 |
< |
// D(bug("VideoDoDriverIO space %p, command %p, contents %p, code %d, kind %d\n", spaceID, commandID, commandContents, commandCode, commandKind)); |
879 |
> |
// D(bug("VideoDoDriverIO space %08x, command %08x, contents %08x, code %d, kind %d\n", spaceID, commandID, commandContents, commandCode, commandKind)); |
880 |
|
int16 err = noErr; |
881 |
|
|
882 |
|
switch (commandCode) { |
883 |
|
case kInitializeCommand: |
884 |
|
case kReplaceCommand: |
885 |
< |
if (private_data != NULL) // Might be left over from a reboot |
886 |
< |
delete private_data->gammaTable; |
885 |
> |
if (private_data != NULL) { // Might be left over from a reboot |
886 |
> |
if (private_data->gammaTable) |
887 |
> |
Mac_sysfree(private_data->gammaTable); |
888 |
> |
if (private_data->regEntryID) |
889 |
> |
Mac_sysfree(private_data->regEntryID); |
890 |
> |
} |
891 |
|
delete private_data; |
892 |
|
|
893 |
< |
iocic_tvect = (uint32)FindLibSymbol("\021DriverServicesLib", "\023IOCommandIsComplete"); |
893 |
> |
iocic_tvect = FindLibSymbol("\021DriverServicesLib", "\023IOCommandIsComplete"); |
894 |
|
D(bug("IOCommandIsComplete TVECT at %08lx\n", iocic_tvect)); |
895 |
|
if (iocic_tvect == 0) { |
896 |
|
printf("FATAL: VideoDoDriverIO(): Can't find IOCommandIsComplete()\n"); |
897 |
|
err = -1; |
898 |
|
break; |
899 |
|
} |
900 |
< |
vslnewis_tvect = (uint32)FindLibSymbol("\020VideoServicesLib", "\026VSLNewInterruptService"); |
900 |
> |
vslnewis_tvect = FindLibSymbol("\020VideoServicesLib", "\026VSLNewInterruptService"); |
901 |
|
D(bug("VSLNewInterruptService TVECT at %08lx\n", vslnewis_tvect)); |
902 |
|
if (vslnewis_tvect == 0) { |
903 |
|
printf("FATAL: VideoDoDriverIO(): Can't find VSLNewInterruptService()\n"); |
904 |
|
err = -1; |
905 |
|
break; |
906 |
|
} |
907 |
< |
vsldisposeis_tvect = (uint32)FindLibSymbol("\020VideoServicesLib", "\032VSLDisposeInterruptService"); |
907 |
> |
vsldisposeis_tvect = FindLibSymbol("\020VideoServicesLib", "\032VSLDisposeInterruptService"); |
908 |
|
D(bug("VSLDisposeInterruptService TVECT at %08lx\n", vsldisposeis_tvect)); |
909 |
|
if (vsldisposeis_tvect == 0) { |
910 |
|
printf("FATAL: VideoDoDriverIO(): Can't find VSLDisposeInterruptService()\n"); |
911 |
|
err = -1; |
912 |
|
break; |
913 |
|
} |
914 |
< |
vsldois_tvect = (uint32)FindLibSymbol("\020VideoServicesLib", "\025VSLDoInterruptService"); |
914 |
> |
vsldois_tvect = FindLibSymbol("\020VideoServicesLib", "\025VSLDoInterruptService"); |
915 |
|
D(bug("VSLDoInterruptService TVECT at %08lx\n", vsldois_tvect)); |
916 |
|
if (vsldois_tvect == 0) { |
917 |
|
printf("FATAL: VideoDoDriverIO(): Can't find VSLDoInterruptService()\n"); |
918 |
|
err = -1; |
919 |
|
break; |
920 |
|
} |
921 |
< |
nqdmisc_tvect = (uint32)FindLibSymbol("\014InterfaceLib", "\007NQDMisc"); |
921 |
> |
nqdmisc_tvect = FindLibSymbol("\014InterfaceLib", "\007NQDMisc"); |
922 |
|
D(bug("NQDMisc TVECT at %08lx\n", nqdmisc_tvect)); |
923 |
|
if (nqdmisc_tvect == 0) { |
924 |
|
printf("FATAL: VideoDoDriverIO(): Can't find NQDMisc()\n"); |
927 |
|
} |
928 |
|
|
929 |
|
private_data = new VidLocals; |
930 |
< |
private_data->gammaTable = NULL; |
931 |
< |
memcpy(private_data->regEntryID, (uint8 *)commandContents + 2, 16); // DriverInitInfo.deviceEntry |
930 |
> |
private_data->gammaTable = 0; |
931 |
> |
private_data->regEntryID = Mac_sysalloc(sizeof(RegEntryID)); |
932 |
> |
if (private_data->regEntryID == 0) { |
933 |
> |
printf("FATAL: VideoDoDriverIO(): Can't allocate service owner\n"); |
934 |
> |
err = -1; |
935 |
> |
break; |
936 |
> |
} |
937 |
> |
Mac2Mac_memcpy(private_data->regEntryID, commandContents + 2, 16); // DriverInitInfo.deviceEntry |
938 |
|
private_data->interruptsEnabled = false; // Disable interrupts |
939 |
|
break; |
940 |
|
|
941 |
|
case kFinalizeCommand: |
942 |
|
case kSupersededCommand: |
943 |
< |
if (private_data != NULL) |
944 |
< |
delete private_data->gammaTable; |
943 |
> |
if (private_data != NULL) { |
944 |
> |
if (private_data->gammaTable) |
945 |
> |
Mac_sysfree(private_data->gammaTable); |
946 |
> |
if (private_data->regEntryID) |
947 |
> |
Mac_sysfree(private_data->regEntryID); |
948 |
> |
} |
949 |
|
delete private_data; |
950 |
|
private_data = NULL; |
951 |
|
break; |
952 |
|
|
953 |
|
case kOpenCommand: |
954 |
< |
err = VideoOpen((uint32)commandContents, private_data); |
954 |
> |
err = VideoOpen(commandContents, private_data); |
955 |
|
break; |
956 |
|
|
957 |
|
case kCloseCommand: |
958 |
< |
err = VideoClose((uint32)commandContents, private_data); |
958 |
> |
err = VideoClose(commandContents, private_data); |
959 |
|
break; |
960 |
|
|
961 |
|
case kControlCommand: |
962 |
< |
err = VideoControl((uint32)commandContents, private_data); |
962 |
> |
err = VideoControl(commandContents, private_data); |
963 |
|
break; |
964 |
|
|
965 |
|
case kStatusCommand: |
966 |
< |
err = VideoStatus((uint32)commandContents, private_data); |
966 |
> |
err = VideoStatus(commandContents, private_data); |
967 |
|
break; |
968 |
|
|
969 |
|
case kReadCommand: |