summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/video/xbox_nv2a.cpp
blob: 3052cad06442ee8c28ac6630a40605f313ac4452 (plain) (tree)
1
2
3
4
5
6
7
8
9
                       
                                    


                       
                            
                               
                 
 
                  
                                            










































































































































                                                                                                                                                                              

                            


                           

                            


                           

                            


                           

                            

















































































































































































































































































                                                                                            

                                  










































                                                                      

                                                                       
















                                                                                                                            

                                      

















































                                                                                          
                                           










































































                                                                                                                     
                                                             















































                                                                                                                  
                                    
                                           
                                       




                                                     
                                        
                                          
                                       






















































                                                                                                                
                        




                                                               
                        




                                                                                  
                        


                                                                                                                                           
                        


                                                                                                                                                              
                        


                                                                                                                                                                                 
                        




                                                               
                        




                                                                    
                         




                                                                    
                         




                                                                           
                         






























                                                                                                             
                        
                                                                                    
                      
                        
                                                                                         
                      
                        



                                                                                                                
                      
                        
                                                           
                                                                       




                                               
                        

                                                                                               
               



                                                                                                                





                                                         
















                                                                                                       
                                                                                                
 
                               












                                                          
                                                                                                
 
                               


















                                                                 

                                                       





                                                                    
                                                                
 



                                                                           


                                        
                                                     



















                                               
                                                              
 



                                                                             
 

                                           
                                                                                  




                                                  
                             
                                                            

 
                                                                                              
 


                                                                    

















                                                                    










                                    
                                                     






                                    
                                                     
     

   
                                                            
 
                          









                                                                                                         
                                                            
 
                          









                                                                                                         
                                                      
 
                        








                                                                                          
                                                                   
 

                                            

                                                               

                        
                       
                         

                              















                                                   
                                         
                                       
                                                                                                                                    
                                                                                       
                                   



                            
                                          


                                                                                        































                                                                                         
                                   



                            
                                                 



                                                                                        



















                                                                                            
                                       
                                                                                                                                    
                                                                                           
                                                           
                                       
                                                                                                                                    
                                                                                           
                                                           
                                     
                                                                                                                                    
                                                                                         
                                                                  
                                          
                                                                  
                                                                                 
                                            
                                                                  
                                                                                 
                                   



                            
                                                 





                                                                                        











































































                                                                                            
                                                                     
 




                         
 
                                                        
                                                                                                                         
                                           
                                                                              






                                                                            
                                           
                                       
                                                                        




                                                       
                                         

                                                  
                                                                      





                                           
                                       
                                         
                                                                      




                                           
                                       
                                   
                                                         



                                

                               
         
                       

 
                                                                        
 





                                               


                            
                                                         
                       
                                          
                       
                            
                                            
                                                                      






                                                                                                 



                                                                        
                                  
         
                                                                         






                                                                                                 
                                                                                    


                                             
                                  

              

                                  


                               



                                   







                                                   
                                                       
                                       
                                                        

                                      
                                                      


                                                            
                                                        


                                                           
                                                       


                                                            
                                                        


                                                           
                                                         


                                                            
                                                          










                                                            
                                               
                                               
                              
                                              

                                                       
                              
                                               

                                                       
                              
                                                

                                                       
                              
                                                 

                                                       
                              
                                                  

                                                       
                              
                                                

                                                       
                              
                                                
                        
                              


                                                  
                                                     

                                         
                                                       

                                                  
                                                   

                                      
                                                      

                                                   
                                                   


                                               
                                                   


                                               
                                                        




                                                 
                                                        





                                                   
                                                                                      


                                                             
                                                                                         
                                                    
                                                              
                         






                                         
                                                       

                                                     
                                                      


                                                             
                                                       


                                                             
                                                        


                                                             
                                                         


                                                             
                                                          


                                                             
                                                        


                                                             
                                                        




                                                   
                                                     

                                         
                                                       

                                                  
                                                   

                                      
                                                      

                                                   
                                                   


                                               
                                                   


                                               
                                                        




                                                 
                                                        





                                                   
                                                                                      


                                                             
                                                                                         
                                                    
                                                              
                         


                                           
                                             
                                 
                              
                                               
                                          
                              
                                           
                        
                              
                                              
                                           
                              
                                           

                                       
                              
                                           

                                       
                              
                                                



                                         
                              
                                                

                                       
                            
                                           

                              



                                                
                                                     

                                                              
                                                    


                                                                
                                                          




                                             
                                                                    




                                                   
                                                          

                                                                 
                                                                    

                                                                       
                                                          

                                                                  
                                                                    

                                                                        
                                                               




                                             
                                                                         




                                                   
                                                               

                                                                  
                                                                         

                                                                        
                                                                   







                                                         
                                                     
                                                     


                                                              
                                                    

                                                                
                                                          




                                            
                                                                    




                                                  
                                                          

                                                                 
                                                                    

                                                                       
                                                          

                                                                  
                                                                    

                                                                        
                                                               




                                             
                                                                         




                                                   
                                                               

                                                                  
                                                                         

                                                                        

                                         
                                                           












                                                                          
                                                                












                                                                          
                                                                        












                                                                          
                                                      












                                                    
                                                      












                                                    





                                            
                                                   




                                         
                                                 




                                                    
                                                         




                                                            
                                                  

                                      
                                                          




                                                            
                                                  




                                             
                                                 




                                                    
                                                




                                                    
                                                 




                                                            
                                                   




                                                            
                                                    




                                                   
                                                        




                                                            
                                                           




                                                  
                                                         




                                                            
                                                  




                                                            
                                                 




                                           

                 
                              
                                 
 

                                                                                                                  

                                                           
                                               
                                                                                         
                                                          
                              

                                                          
                                                
                              
                                                 
                                                
                              
                                           
                                           
                              

                              
                 
         

                                
                                                                      


                                             
                                                                         
                                    
                                              
         

 
                                                                                                                              
 
                  
 



                                                        
                       



                                                                                                      
                        
                                  
                      


                                                                            



                                                                                                                                                             
                                                                                                                                        
                                                                                                                                       
                                                       



                    
                                                                                                                                       
 
                  
                          



                                                   



                                                        
                       



                                                                                                      

                           
                      

                                                                            
                                                                     

                                                                                                                                                                                                                                                      

                      

                                                                                                                                                                                                    
                 
                                                        
                                                                                                                                       
                                                       



                    
                                                                                                                                           
 
                      

                           

                          

              


                                                                            



                                                        
                       



                                                                                                      
                                                                                                            



                                                        



                                                                                                                                                             




                                                                                                                                        
                                                                    

                                                                                                                                                                                                                                                  

                                      

                                                                                                                                                                                                
                                 























                                                                            
                                                                                                                                       
                                                       

                    























































                                                      
                               




















































































                                                                                                      























                                                                                                                           
                                                                                                                       







































































                                                 

                                                                                                     
                   



                                            
                                     








                                                                                       
                                         
                                                  
                                            


                                                                            
                      
                                          





                                                                            
                                                                                            
                                                  

                                                                                                                                        
                      





                                                                                 


         

                                                                                                                   
 
                   





                                                        
                                                                                       


                                              
                                                                                                                                                            


                                   
                                                                   
                                    
         
                     

 

                                                                                                             
 
                   




                                                        
                                     
                                                                                       


                                              







                                                                                                                                     
                                                          
                                                                                                                   
 
                           






                                                                          
                                                                                       











                                                                                                                


































                                                                                   
                                                                                                  
 
                          
                 
                   




                                                                           
                                               
                                             




                                                                                                      
                                                

                                                                                                               
                                                                                       
                                                                                                                                         

                                                                                   

                                                                                                                                     




                                 

                                                                                                 
                                                                                                                         

                                             
                                                                      

                                                                                                         
                                                                                                                                         

                                                                                 

                                                                                                                                   
                         
                                                                                                      



                 
                                                                 
 

                           



                        


































                                                         























                                                                                                                           
                                                





                                                                                             







                                                                                                                                         

                                                                        


                                                                  

                                                                        

                                                         

                                                                        

                                                   
                                                                        







                                                                 
                                                            


                                                                  
                                                            

                                                         
                                                            






                                                   

                 
                                  


      
                                                                
 

                           




                        
 

                       





































                                                                                       
                                               



                                                                                            
         
 




                                                                 

                                                                       

                                                         

                                                                       


                                       
                         


                                                                 

                                                                       

                                                         

                                                                       


                                       

                         

 
                                                                                                                                                                             

                     
                                                          



                                                                                      

                                     
                         
         

                                                                                       

















                                                                                              
                             
                 

 
                                                                         
 

                               
                       
                
                                           
 


                     
                                                        

                            
                                                                

                                        

                                                                                                       


                                                                                                      
                                                    




                                                                                                                          




                                                                  





                                    




                                                                                                                                                                              
                            
                           
               


                                                                                              



                                                         




























                                                                                                                                  


                                                
                                            





                                                                                                                    
         
                                            




                                                                                                                    





                                                                                                                                

                                                                                                 


                 

                                                                                                  

                                       






                                                                                                        

                                                                                                                                                                                         









                                                                                                        
                                                                                                                                                                                                                                           





















                                                                                                               
                                                                                                                                                                                      






















                                                                                                               
                                                                                                                                                                                                                   
                                    
                                                                                                                                                                                                                   























                                                                                                                           

                                                                                                                                                                                                                       










                                                                                                      
                         
         
                                                        

 
                                                                                     
 
                      
















                                                                     





                                                                                   
                                                                                                                                                     
 

                          



                                                                 
               
                                                                      
      
                                 
                                                                      



                                       
                                                                                       
                                                                      






                                                                                                                                                                                                                                                                                

                         

                                 
                                       


                                      
                                                      
                                
                                                                                                                      
                                                                                                                         
                                                    
                                                                                                                     
                            
                                                                                                            
                 



                                 
                                  
                           


                                            
               
                                                          
      



                                                                                                     


                           
                                                           
                         
 



                                       

                                                                                                
                                                                                             
                                      

                              
                                                         
                                                                  
                                        

                                                                                       
                                                                          
                         
                              
                                                                



                                                                          
                                                                                                   

                                                                                                        


                                 




                                                                                                                                                          
                                      

                              
                                                                                                    

                                                
                                                                                                  
                                             
                                      

                                                  
                                                                                                     
                                                                 
                 





                                                                                      
 






                                                                                                 
                 




                                                                          

                                            
 

                                                                               








                                                                                         



                                                









                                                                                         
                                                                                       

                                        

                                            
 

                                                                                    








                                                                                                 
 












                                                                                                 












                                                                                        
                                                                       

                                                          
                                                 

                                                                                        
                                             

                                                                                        
                                                 

                                                                                        
                                              

                                                                                        
                                                    
















                                                                                                                            
                                                        
                           








                                                                    







                                                                                     

                                                 





                                                                               

                                                                                             

                           

                                         

                                                                                        

                           
                                 




                                              


                                 




                                              

                           
                                 
                                                          
                                    
                                                                                                             
                                                                                                    

                           

                                                         
 
                                           

                                          
                                                      
         

                                                         
 
                                           

                                          



                                                                
                                                              


                                                                
                                                              

                                 


                                                              


                                                                                    

                                                                                        
                                                              
                                                   
                                               

                                                    


                                                          

                                                    
                                           


                                                    
                                                                                                                       


                                                    
                                                                                                           

                                 

                                                        
                                                              
               
                                                                                                   
      


                                 






                                                        
                                                         
                            
                                                         
                                 
                 

                                 
         

                                 
                                              



                                                            











                                                                                       

                                       
                                                                   


                                                          



                                   
                                                                  


                                                        





                                                                                    





                                               
                                                      









                                                     



                                               
                                                          
         











                                           
                                 
                                                                                   







                                                    
                                                        









                                    
                                                        

                                 
                                                         

                                 
                                                         
         
                                 
                                                                

                                 
                                                                     




                                   
                                                           








                                                                                                      
                                                        








                                                          

                                                         

                                      
                                                                         








                                                                                    
                                                                    







                                                                 







                                                                                         
                                                                       


















                                                                








                                                                                                                                       
                                                                                                                       

                                    
                                                                                                         

                         
                                           






                                       
                   
                                         




                                                                          
                                         
                                                                 



                                                                   



                                                                 

                           


                                                          
                                                                                      

                           


                                                          
                                                                                                                   

                                                                                                           
                                                                                                             

                                                                                                          



                               
                                                            
                                                                   

                                                                                                       
                                                                                     




                                                          
                                                                                             

                           
                           

                                                          




                                                                                  
                                                                                     

                           
                             

                                                          
                                                                  
                                                               
                                                                                     

                                  
                                                                                                                                                                       
      




                                                          
                                                              
                                                               
                                                                                     



                                                                                                                                                   




                                  
                                                               
                                   
                                                                        
                                   
                                                                                                  
                    
                                                                                 



                                           
                                                                    




                                                               
                                                                   




                                                                                    
                                                                     




                                                             
                                                         
                                                                   



                                                                                                                                                    
                                                                                                                                                   










                                                                                                      
                                                          
                                                                 
                                                                                                                                               
                 
                    
                                                                                                                                               

                                                                    


                                                                                                                                 
                                                                                                                             




                                                                                                                   




























































































































                                                                                      
                 

 
                                                     

                                          






                                                

 
                                               
 

                                               

 


                                                                      
                                           



                                                          
                                                                                   








                                                          
                                                                      
 



                                                        

 
                                                          
 
                            
 



                            


















































































                                                                   
                               
               
                               
               
                               
               
                               
















                                                        
                               

                
                               








                                                                       
                                             
               

                                                
               
                                                           
               
                                                            
               
                                                    
               
                                                     
















                                                                       


                                                  

                      





                                                   

                      


                                                                

                      


                                                                 

                      


                                                         

                      


                                                          











                                   
                                                                    



































































































































































                                                                                                                          


                                                                                                                                          
                                                  


                                                                                              











































                                                                                                                              


                                                                                                                                                               


                                                                

































                                                                                                                                                                        
                                                












































                                                                                                                      


                                                                                                                          





                                                                  


                                                                                                                          




                                                                            


                                                                                                                                  



























                                                                                 
                                                                                                            
                                                                                 
                                                                                                            
                                                
                                                        





                                                                                                                                           
                                                                                                            

 
                                                 
 




                                                       
                                              

                            
                                      


                                            
                                       


                                             
                                         
            
                                         



                                       



                                                




                                                                                                                                 






                                 
                                                                                                                      
 
                                         
                                                                
                                                                    
 


                                                                                


                 
                                                                                                                        





                                               
                                                                                         









                                                               

                                                       

                          

                                  


                                            
                       
 























                                                                                                                                  
                                                     
                                 


















                                                                                                                                               
                                 







                                                                                              
                                 















                                                                                                                                               
                                             













                                                                                                                                               
                                 


                                                                                          
                         



                 








                                       





                                                                                                                         
                                                                                                                         





                                                                           
                                                                                                     


                                                                           
                                                                                                      

                                                                           
                                                      
                                                                                                      


                                                                           
                                                                                                     


                                                                           
                                                                                                   










                                                                                            
                                                                                                                   

                           
                                                                                                            




                                        
                     


                           
                                                                      
                                                                                                                           


                                                                           
                                                            

                                        
                                                                                                                                           


                                                                           
                                                            

                                        
                                                                                                             

                                                                           
                                                
                                                             



















                                                                     
                                                                                                             


                                                                           
                                                            
                               
                               
                                        





                                               
                                     
                                                                                  


                                                             
                 
                                                                                                            


                                                                           
                                                          

                                      
                                                                                                          



                                                                                            
                                                      




                                                         
                                                                                                                                
                                                                           

                                          
                                                                                               
                                                  
 

                                                                    
                                                                                
                                                                                                     

                                                                                                           
                                                                                                            


                                                                                                         
                                                                                                           
                                                                                                          
                         
                                                  





                                                            


                                                                             



                                 
              
                                                                                                                    

                                                
                                                 
                    
                                                 
         
 




                                     
                                                   
 
                                                               
                                                               


                                                                                                                                                            
// license:BSD-3-Clause
// copyright-holders:Samuele Zannoli
#include "emu.h"
#include "video/poly.h"
#include "bitmap.h"
#include "machine/pic8259.h"
#include "includes/xbox_nv2a.h"
#include <bitset>

//#define LOG_NV2A
#define DEBUG_CHECKS // enable for debugging

const char *vertex_program_disassembler::srctypes[] = { "??", "Rn", "Vn", "Cn" };
const char *vertex_program_disassembler::scaops[] = { "NOP", "IMV", "RCP", "RCC", "RSQ", "EXP", "LOG", "LIT", "???", "???", "???", "???", "???", "???", "???", "???", "???" };
const int vertex_program_disassembler::scapar2[] = { 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
const char *vertex_program_disassembler::vecops[] = { "NOP", "MOV", "MUL", "ADD", "MAD", "DP3", "DPH", "DP4", "DST", "MIN", "MAX", "SLT", "SGE", "ARL", "???", "???", "???" };
const int vertex_program_disassembler::vecpar2[] = { 0, 4, 6, 5, 7, 6, 6, 6, 6, 6, 6, 6, 6, 4, 0, 0, 0 };
const char *vertex_program_disassembler::vecouts[] = { "oPos", "???", "???", "oD0", "oD1", "oFog", "oPts", "oB0", "oB1", "oT0", "oT1", "oT2", "oT3" };
const char vertex_program_disassembler::compchar[] = { 'x', 'y', 'z', 'w' };

/*
Each vertex program instruction is a 128 bit word made of the fields:
d         f
w   b     i
o   i     e
r   t     l
d   s     d
+-+-----+-------
|0|31-0 |not used
+-+-----+-------
| |31-29|not used
| +-----+-------
| |28-25|scalar operation
| +-----+-------
| |24-21|vectorial operation
| +-----+-------
| |20-13|index for source constant C[]
| +-----+-------
| |12-9 |input vector index
| +-----+-------
|1|  8  |parameter A:sign
| +-----+-------
| | 7-6 |parameter A:swizzle x
| +-----+-------
| | 5-4 |parameter A:swizzle y
| +-----+-------
| | 3-2 |parameter A:swizzle z
| +-----+-------
| | 1-0 |parameter A:swizzle w
|-+-----+-------
| |31-28|parameter A:parameter Rn index
| +-----+-------
| |27-26|parameter A:input type 1:Rn 2:Vn 3:C[n]
| +-----+-------
| | 25  |parameter B:sign
| +-----+-------
| |24-23|parameter B:swizzle x
| +-----+-------
| |22-21|parameter B:swizzle y
| +-----+-------
| |20-19|parameter B:swizzle z
| +-----+-------
|2|18-17|parameter B:swizzle w
| +-----+-------
| |16-13|parameter B:parameter Rn index
| +-----+-------
| |12-11|parameter B:input type 1:Rn 2:Vn 3:C[n]
| +-----+-------
| | 10  |parameter C:sign
| +-----+-------
| | 9-8 |parameter C:swizzle x
| +-----+-------
| | 7-6 |parameter C:swizzle y
| +-----+-------
| | 5-4 |parameter C:swizzle z
| +-----+-------
| | 3-2 |parameter C:swizzle w
| +-----+-------
| | 1-0 |
|-+     |parameter C:parameter Rn index
| |31-30|
| +-----+-------
| |29-28|parameter C:input type 1:Rn 2:Vn 3:C[n]
| +-----+-------
| |27-24|output Rn mask from vectorial operation
| +-----+-------
| |23-20|output Rn index from vectorial operation
| +-----+-------
| |19-16|output Rn mask from scalar operation
| +-----+-------
|3|15-12|output vector write mask
| +-----+-------
| | 11  |1:output is output vector 0:output is constant C[]
| +-----+-------
| |10-3 |output vector/constant index
| +-----+-------
| |  2  |0:output Rn from vectorial operation 1:output Rn from scalar operation
| +-----+-------
| |  1  |1:add a0x to index for source constant C[]
| +-----+-------
| |  0  |1:end of program
+-+-----+-------
Each vertex program instruction can generate up to three destination values using up to three source values.
The first possible destination is to Rn from a vectorial operation.
The second possible destination is to a vertex shader output or C[n] from a vectorial or scalar operation.
The third possible destination is to Rn from a scalar operation.
*/
void vertex_program_disassembler::decodefields(unsigned int *dwords, int offset, fields &decoded)
{
	unsigned int srcbits[3];
	int a;

	srcbits[0] = ((dwords[1 + offset] & 0x1ff) << 6) | (dwords[2 + offset] >> 26);
	srcbits[1] = (dwords[2 + offset] >> 11) & 0x7fff;
	srcbits[2] = ((dwords[2 + offset] & 0x7ff) << 4) | (dwords[3 + offset] >> 28);
	decoded.ScaOperation = (int)(dwords[1 + offset] >> 25) & 0xf;
	decoded.VecOperation = (int)(dwords[1 + offset] >> 21) & 0xf;
	decoded.SourceConstantIndex = (int)(dwords[1 + offset] >> 13) & 0xff;
	decoded.InputIndex = (int)(dwords[1 + offset] >> 9) & 0xf;
	for (a = 0; a < 3; a++)
	{
		decoded.src[a].Sign = (int)(srcbits[a] >> 14) & 1;
		decoded.src[a].SwizzleX = (int)(srcbits[a] >> 12) & 3;
		decoded.src[a].SwizzleY = (int)(srcbits[a] >> 10) & 3;
		decoded.src[a].SwizzleZ = (int)(srcbits[a] >> 8) & 3;
		decoded.src[a].SwizzleW = (int)(srcbits[a] >> 6) & 3;
		decoded.src[a].TempIndex = (int)(srcbits[a] >> 2) & 0xf;
		decoded.src[a].ParameterType = (int)(srcbits[a] >> 0) & 3;
	}

	decoded.VecTempWriteMask = (int)(dwords[3 + offset] >> 24) & 0xf;
	decoded.VecTempIndex = (int)(dwords[3 + offset] >> 20) & 0xf;
	decoded.ScaTempWriteMask = (int)(dwords[3 + offset] >> 16) & 0xf;
	decoded.OutputWriteMask = (int)(dwords[3 + offset] >> 12) & 0xf;
	decoded.OutputSelect = (int)(dwords[3 + offset] >> 11) & 0x1;
	decoded.OutputIndex = (int)(dwords[3 + offset] >> 3) & 0xff;
	decoded.MultiplexerControl = (int)(dwords[3 + offset] >> 2) & 0x1;
	decoded.Usea0x = (int)(dwords[3 + offset] >> 1) & 0x1;
	decoded.EndOfProgram = (int)(dwords[3 + offset] >> 0) & 0x1;
}

int vertex_program_disassembler::disassemble_mask(int mask, char *s)
{
	int l;

	*s = 0;
	if (mask == 15)
		return 0;
	s[0] = '.';
	l = 1;
	if ((mask & 8) != 0)
	{
		s[l] = 'x';
		l++;
	}
	if ((mask & 4) != 0)
	{
		s[l] = 'y';
		l++;
	}
	if ((mask & 2) != 0)
	{
		s[l] = 'z';
		l++;
	}
	if ((mask & 1) != 0)
	{
		s[l] = 'w';
		l++;
	}
	s[l] = 0;
	return l;
}

int vertex_program_disassembler::disassemble_swizzle(sourcefields f, char *s)
{
	int t, l;

	t = 4;
	if (f.SwizzleW == 3)
	{
		t = t - 1;
		if (f.SwizzleZ == 2)
		{
			t = t - 1;
			if (f.SwizzleY == 1)
			{
				t = t - 1;
				if (f.SwizzleX == 0)
				{
					t = t - 1;
				}
			}
		}
	}
	*s = 0;
	if (t == 0)
		return 0;
	s[0] = '.';
	l = 1;
	if (t > 0)
	{
		s[l] = compchar[f.SwizzleX];
		l++;
	}
	if (t > 1)
	{
		s[l] = compchar[f.SwizzleY];
		l++;
	}
	if (t > 2)
	{
		s[l] = compchar[f.SwizzleZ];
		l++;
	}
	if (t > 3)
	{
		s[l] = compchar[f.SwizzleW];
		l++;
	}
	s[l] = 0;
	return l;
}

int vertex_program_disassembler::disassemble_source(sourcefields f, fields fi, char *s)
{
	int l;

	if (f.ParameterType == 0) {
		strcpy(s, ",???");
		return 4;
	}
	l = 0;
	if (f.Sign != 0) {
		s[l] = '-';
		l++;
	}
	if (f.ParameterType == 1) {
		s[l] = 'r';
		l = l + 1 + sprintf(s + l + 1, "%d", f.TempIndex);
	}
	else if (f.ParameterType == 2){
		s[l] = 'v';
		l = l + 1 + sprintf(s + l + 1, "%d", fi.InputIndex);
	}
	else
	{
		if (fi.Usea0x != 0)
		{
			if (fi.SourceConstantIndex >= 96) {
				strcpy(s + l, "c[");
				l = l + 2;
				l = l + sprintf(s + l, "%d", fi.SourceConstantIndex - 96);
				strcpy(s + l, "+a0.x]");
				l = l + 6;
			}
			else {
				strcpy(s + l, "c[a0.x");
				l = l + 6;
				l = l + sprintf(s + l, "%d", fi.SourceConstantIndex - 96);
				s[l] = ']';
				l++;
			}
		}
		else {
			strcpy(s + l, "c[");
			l = l + 2;
			l = l + sprintf(s + l, "%d", fi.SourceConstantIndex - 96);
			s[l] = ']';
			l++;
		}
	}
	l = l + disassemble_swizzle(f, s + l);
	s[l] = 0;
	return l;
}

int vertex_program_disassembler::disassemble_output(fields f, char *s)
{
	int l;

	if (f.OutputSelect == 1) {
		strcpy(s, vecouts[f.OutputIndex]);
		return strlen(s);
	}
	else {
		strcpy(s, "c[");
		l = 2;
		l = l + sprintf(s + l, "%d", f.OutputIndex - 96);
		s[l] = ']';
		l++;
	}
	s[l] = 0;
	return l;
}

int vertex_program_disassembler::output_types(fields f, int *o)
{
	o[0] = o[1] = o[2] = o[3] = o[4] = o[5] = 0;
	if ((f.VecOperation > 0) && (f.VecTempWriteMask != 0))
		o[0] = 1;
	if ((f.VecOperation > 0) && (f.OutputWriteMask != 0) && (f.MultiplexerControl == 0))
		o[1] = 1;
	if ((f.ScaOperation > 0) && (f.OutputWriteMask != 0) && (f.MultiplexerControl == 1))
		o[2] = 1;
	if ((f.ScaOperation > 0) && (f.ScaTempWriteMask != 0))
		o[3] = 1;
	if (f.VecOperation == 13)
		o[4] = 1;
	if (f.EndOfProgram == 1)
		o[5] = 1;
	return o[0] + o[1] + o[2] + o[3] + o[4] + o[5];
}

int vertex_program_disassembler::disassemble(unsigned int *instruction, char *line)
{
	int b, p;
	char *c;

	if (state == 0) {
		decodefields(instruction, 0, f);
		output_types(f, o);
		state = 1;
	}
	if (o[0] != 0)
	{
		o[0] = 0;
		c = line;
		strcpy(c, vecops[f.VecOperation]);
		c = c + strlen(c);
		strcpy(c, " r");
		c = c + 2;
		c = c + sprintf(c, "%d", f.VecTempIndex);
		c = c + disassemble_mask(f.VecTempWriteMask, c);
		b = 0;
		for (p = 4; p != 0; p = p >> 1)
		{
			if ((vecpar2[f.VecOperation] & p) != 0) {
				c[0] = ',';
				c++;
				c = c + disassemble_source(f.src[b], f, c);
			}
			b++;
		}
		*c = 0;
		return 1;
	}
	if (o[1] != 0)
	{
		o[1] = 0;
		c = line;
		strcpy(c, vecops[f.VecOperation]);
		c = c + strlen(c);
		*c = ' ';
		c++;
		c = c + disassemble_output(f, c);
		c = c + disassemble_mask(f.OutputWriteMask, c);
		b = 0;
		for (p = 4; p != 0; p = p >> 1)
		{
			if ((vecpar2[f.VecOperation] & p) != 0) {
				*c = ',';
				c++;
				c = c + disassemble_source(f.src[b], f, c);
			}
			b++;
		}
		*c = 0;
		return 1;
	}
	if (o[2] != 0)
	{
		o[2] = 0;
		c = line;
		strcpy(c, scaops[f.ScaOperation]);
		c = c + strlen(c);
		*c = ' ';
		c++;
		c = c + disassemble_output(f, c);
		c = c + disassemble_mask(f.OutputWriteMask, c);
		b = 0;
		for (p = 4; p != 0; p = p >> 1)
		{
			if ((scapar2[f.ScaOperation] & p) != 0) {
				*c = ',';
				c++;
				c = c + disassemble_source(f.src[b], f, c);
			}
			b++;
		}
		*c = 0;
		return 1;
	}
	if (o[3] != 0)
	{
		if (f.VecOperation > 0)
			b = 1;
		else
			b = f.VecTempIndex;
		o[3] = 0;
		c = line;
		strcpy(c, scaops[f.ScaOperation]);
		c = c + strlen(c);
		strcpy(c, " r");
		c = c + 2;
		c = c + sprintf(c, "%d", b);
		c = c + disassemble_mask(f.ScaTempWriteMask, c);
		b = 0;
		for (p = 4; p != 0; p = p >> 1)
		{
			if ((scapar2[f.ScaOperation] & p) != 0) {
				*c = ',';
				c++;
				c = c + disassemble_source(f.src[b], f, c);
			}
			b++;
		}
		*c = 0;
		return 1;
	}
	if (o[4] != 0)
	{
		o[4] = 0;
		c = line;
		c = c + sprintf(c, "MOV a0.x,");
		c = c + disassemble_source(f.src[0], f, c);
		*c = 0;
		return 1;
	}
	if (o[5] != 0)
	{
		o[5] = 0;
		strcpy(line, "END");
		return 1;
	}
	state = 0;
	return 0;
}

vertex_program_simulator::vertex_program_simulator()
{
	for (auto & elem : op)
		elem.modified = 0;
	initialize_constants();
}

void vertex_program_simulator::set_data(vertex_nv *in, vertex_nv *out)
{
	input = in;
	output = out;
}

void vertex_program_simulator::reset()
{
	ip = 0;
	a0x = 0;
	initialize_outputs();
	initialize_temps();
}

void vertex_program_simulator::decode_instruction(int address)
{
	instruction *i;

	i = &op[address];
	i->d.SignA = i->i[1] & (1 << 8);
	i->d.ParameterTypeA = (i->i[2] >> 26) & 3;
	i->d.TempIndexA = (i->i[2] >> 28) & 15;
	i->d.SwizzleA[0] = (i->i[1] >> 6) & 3;
	i->d.SwizzleA[1] = (i->i[1] >> 4) & 3;
	i->d.SwizzleA[2] = (i->i[1] >> 2) & 3;
	i->d.SwizzleA[3] = (i->i[1] >> 0) & 3;
	i->d.SignB = i->i[2] & (1 << 25);
	i->d.ParameterTypeB = (i->i[2] >> 11) & 3;
	i->d.TempIndexB = (i->i[2] >> 13) & 15;
	i->d.SwizzleB[0] = (i->i[2] >> 23) & 3;
	i->d.SwizzleB[1] = (i->i[2] >> 21) & 3;
	i->d.SwizzleB[2] = (i->i[2] >> 19) & 3;
	i->d.SwizzleB[3] = (i->i[2] >> 17) & 3;
	i->d.SignC = i->i[2] & (1 << 10);
	i->d.ParameterTypeC = (i->i[3] >> 28) & 3;
	i->d.TempIndexC = ((i->i[2] & 3) << 2) + (i->i[3] >> 30);
	i->d.SwizzleC[0] = (i->i[2] >> 8) & 3;
	i->d.SwizzleC[1] = (i->i[2] >> 6) & 3;
	i->d.SwizzleC[2] = (i->i[2] >> 4) & 3;
	i->d.SwizzleC[3] = (i->i[2] >> 2) & 3;
	i->d.VecOperation = (VectorialOperation)((i->i[1] >> 21) & 15);
	i->d.ScaOperation = (ScalarOperation)((i->i[1] >> 25) & 15);
	i->d.OutputWriteMask = ((i->i[3] >> 12) & 15);
	i->d.MultiplexerControl = i->i[3] & 4; // 0 : output Rn from vectorial operation 4 : output Rn from scalar operation
	i->d.VecTempIndex = (i->i[3] >> 20) & 15;
	i->d.OutputIndex = (i->i[3] >> 3) & 255;
	i->d.OutputSelect = i->i[3] & 0x800;
	i->d.VecTempWriteMask = (i->i[3] >> 24) & 15;
	i->d.ScaTempWriteMask = (i->i[3] >> 16) & 15;
	i->d.InputIndex = (i->i[1] >> 9) & 15;
	i->d.SourceConstantIndex = (i->i[1] >> 13) & 255;
	i->d.Usea0x = i->i[3] & 2;
	i->d.EndOfProgram = i->i[3] & 1;
}

int vertex_program_simulator::step()
{
	int p1, p2;
	float tmp[3 * 4];
	float tmpv[4] = { 0, 0, 0, 0};
	float tmps[4] = { 0, 0, 0, 0};
	instruction::decoded *d;

#if 0 // useful while debugging to see what instrucion is being executed
	static int debugvpi = 0;
	char disbuffer[256];
	if (debugvpi) {
		char *pp;
		vertex_program_disassembler vdis;

		pp = disbuffer;
		while (vdis.disassemble(op[ip].i, pp) != 0) {
			pp = pp + strlen(pp);
			*pp = '\n';
			pp++;
			*pp = 0;
		}
	}
#endif

	if (op[ip].modified)
		decode_instruction(ip);
	d = &(op[ip].d);
	// prepare inputs
	//  input A
	generate_input(&tmp[0], d->SignA, d->ParameterTypeA, d->TempIndexA, d->SwizzleA);
	//  input B
	generate_input(&tmp[4], d->SignB, d->ParameterTypeB, d->TempIndexB, d->SwizzleB);
	//  input C
	generate_input(&tmp[8], d->SignC, d->ParameterTypeC, d->TempIndexC, d->SwizzleC);
	// compute 2 instructions
	//  vectorial
	compute_vectorial_operation(tmpv, d->VecOperation, tmp);
	//  scalar
	compute_scalar_operation(tmps, d->ScaOperation, tmp);
	// assign destinations
	if (d->VecOperation > 0) {
		if (d->VecOperation == 13)
			//o[4] = 1;
			a0x = (int)tmpv[0];
		else {
			if (d->VecTempWriteMask != 0) { // assign to Rn
				//o[0] = 1;
				int wm = d->VecTempWriteMask;
				for (p1 = 0; p1 < 4; p1++) {
					if (wm & 8)
						r_temp[d->VecTempIndex].fv[p1] = tmpv[p1];
					wm = wm << 1;
				}
			}
			if ((d->OutputWriteMask != 0) && (d->MultiplexerControl == 0)) {
				//o[1] = 1;
				if (d->OutputSelect) { // assign to output
					int wm = d->OutputWriteMask;
					for (p1 = 0; p1 < 4; p1++) {
						if (wm & 8)
							output->attribute[d->OutputIndex].fv[p1] = tmpv[p1];
						wm = wm << 1;
					}
					// remeber, output position == r12
					if (d->OutputIndex == 0)
						for (p1 = 0; p1 < 4; p1++) {
							r_temp[12].fv[p1] = output->attribute[d->OutputIndex].fv[p1];
						}
				}
				else { // assign to constant
					int wm = d->OutputWriteMask;
					for (p1 = 0; p1 < 4; p1++) {
						if (wm & 8)
							c_constant[d->OutputIndex].fv[p1] = tmpv[p1];
						wm = wm << 1;
					}
				}
			}
		}
	}
	if (d->ScaOperation > 0) {
		if (d->ScaTempWriteMask != 0) { // assign to Rn
			//o[3] = 1;
			if (d->VecOperation > 0)
				p2 = 1;
			else
				p2 = d->VecTempIndex;
			int wm = d->ScaTempWriteMask;
			for (p1 = 0; p1 < 4; p1++) {
				if (wm & 8)
					r_temp[p2].fv[p1] = tmps[p1];
				wm = wm << 1;
			}
		}
		if ((d->OutputWriteMask != 0) && (d->MultiplexerControl != 0)) { // assign to output
			//o[2] = 1;
			int wm = d->OutputWriteMask;
			for (p1 = 0; p1 < 4; p1++) {
				if (wm & 8)
					output->attribute[d->OutputIndex].fv[p1] = tmps[p1];
				wm = wm << 1;
			}
			// remeber, output position == r12
			if (d->OutputIndex == 0) {
				for (p1 = 0; p1 < 4; p1++) {
					r_temp[12].fv[p1] = output->attribute[d->OutputIndex].fv[p1];
				}
			}
		}
	}
	return d->EndOfProgram;
}

void vertex_program_simulator::execute()
{
	int c;

	c = 0;
	do {
		c = step();
		ip++;
	} while (c == 0);
}

void vertex_program_simulator::jump(int address)
{
	ip = address;
}

void vertex_program_simulator::process(int address, vertex_nv *in, vertex_nv *out, int count)
{
#if 1 // useful while debugging to see what is being executed
	static int debugvps = 0;
	if (debugvps) {
		char *pp;
		vertex_program_disassembler vdis;
		char disbuffer[128];

		jump(address);
		debugvps--;
		for (int t = 0; t < 128; t++) {
			pp = disbuffer;
			while (vdis.disassemble(op[ip + t].i, pp) != 0) {
				pp = pp + strlen(pp);
				*pp = '\n';
				pp++;
				*pp = 0;
			}
			printf("%08X %08X %08X %s", op[ip + t].i[1], op[ip + t].i[2], op[ip + t].i[3], disbuffer);
			if (op[ip + t].i[3] & 1)
				break;
		}
	}
#endif
	set_data(in, out);
	while (count > 0) {
		reset();
		jump(address);
		execute();
		input++;
		output++;
		count--;
	}
}

int vertex_program_simulator::status()
{
	return ip;
}

void vertex_program_simulator::initialize_outputs()
{
	for (int n = 0; n < 16; n++) {
		output->attribute[n].fv[0] = output->attribute[n].fv[1] = output->attribute[n].fv[2] = 0;
		output->attribute[n].fv[3] = 1;
	}
}

void vertex_program_simulator::initialize_temps()
{
	for (auto & elem : r_temp) {
		for (int m = 0; m < 4; m++)
			elem.fv[m] = 0;
	}
}

void vertex_program_simulator::initialize_constants()
{
	for (auto & elem : c_constant) {
		for (int m = 0; m < 4;m++)
			elem.fv[m] = 0;
	}
}

void vertex_program_simulator::generate_input(float t[4], int sign, int type, int temp, int swizzle[4])
{
	float sgn = 1;

	if (sign)
		sgn = -1;
	if (type == 1) {
		t[0] = sgn*r_temp[temp].fv[swizzle[0]];
		t[1] = sgn*r_temp[temp].fv[swizzle[1]];
		t[2] = sgn*r_temp[temp].fv[swizzle[2]];
		t[3] = sgn*r_temp[temp].fv[swizzle[3]];
	}
	else if (type == 2) {
		int InputIndex = op[ip].d.InputIndex;
		t[0] = sgn*input->attribute[InputIndex].fv[swizzle[0]];
		t[1] = sgn*input->attribute[InputIndex].fv[swizzle[1]];
		t[2] = sgn*input->attribute[InputIndex].fv[swizzle[2]];
		t[3] = sgn*input->attribute[InputIndex].fv[swizzle[3]];
	}
	else if (type == 3) {
		int SourceConstantIndex = op[ip].d.SourceConstantIndex;
		if (op[ip].d.Usea0x)
			SourceConstantIndex = SourceConstantIndex + a0x;
		t[0] = sgn*c_constant[SourceConstantIndex].fv[swizzle[0]];
		t[1] = sgn*c_constant[SourceConstantIndex].fv[swizzle[1]];
		t[2] = sgn*c_constant[SourceConstantIndex].fv[swizzle[2]];
		t[3] = sgn*c_constant[SourceConstantIndex].fv[swizzle[3]];
	}
}

void vertex_program_simulator::compute_vectorial_operation(float t_out[4], int instruction, float par_in[3 * 4])
{
	const int p1_A = 0;
	const int p2_B = 4;
	const int p3_C = 8;

	// t_out <= instruction(par_in)
	switch (instruction) {
	case 0: // "NOP"
		break;
	case 1: // "MOV"
		t_out[0] = par_in[p1_A + 0];
		t_out[1] = par_in[p1_A + 1];
		t_out[2] = par_in[p1_A + 2];
		t_out[3] = par_in[p1_A + 3];
		break;
	case 2: // "MUL"
		t_out[0] = par_in[p1_A + 0] * par_in[p2_B + 0];
		t_out[1] = par_in[p1_A + 1] * par_in[p2_B + 1];
		t_out[2] = par_in[p1_A + 2] * par_in[p2_B + 2];
		t_out[3] = par_in[p1_A + 3] * par_in[p2_B + 3];
		break;
	case 3: // "ADD"
		t_out[0] = par_in[p1_A + 0] + par_in[p3_C + 0];
		t_out[1] = par_in[p1_A + 1] + par_in[p3_C + 1];
		t_out[2] = par_in[p1_A + 2] + par_in[p3_C + 2];
		t_out[3] = par_in[p1_A + 3] + par_in[p3_C + 3];
		break;
	case 4: // "MAD"
		t_out[0] = par_in[p1_A + 0] * par_in[p2_B + 0] + par_in[p3_C + 0];
		t_out[1] = par_in[p1_A + 1] * par_in[p2_B + 1] + par_in[p3_C + 1];
		t_out[2] = par_in[p1_A + 2] * par_in[p2_B + 2] + par_in[p3_C + 2];
		t_out[3] = par_in[p1_A + 3] * par_in[p2_B + 3] + par_in[p3_C + 3];
		break;
	case 5: // "DP3"
		t_out[0] = par_in[p1_A + 0] * par_in[p2_B + 0] + par_in[p1_A + 1] * par_in[p2_B + 1] + par_in[p1_A + 2] * par_in[p2_B + 2];
		t_out[1] = t_out[2] = t_out[3] = t_out[0];
		break;
	case 6: // "DPH"
		t_out[0] = par_in[p1_A + 0] * par_in[p2_B + 0] + par_in[p1_A + 1] * par_in[p2_B + 1] + par_in[p1_A + 2] * par_in[p2_B + 2] + par_in[p2_B + 3];
		t_out[1] = t_out[2] = t_out[3] = t_out[0];
		break;
	case 7: // "DP4"
		t_out[0] = par_in[p1_A + 0] * par_in[p2_B + 0] + par_in[p1_A + 1] * par_in[p2_B + 1] + par_in[p1_A + 2] * par_in[p2_B + 2] + par_in[p1_A + 3] * par_in[p2_B + 3];
		t_out[1] = t_out[2] = t_out[3] = t_out[0];
		break;
	case 8: // "DST"
		t_out[0] = 1.0;
		t_out[1] = par_in[p1_A + 1] * par_in[p2_B + 1];
		t_out[2] = par_in[p1_A + 2];
		t_out[3] = par_in[p2_B + 3];
		break;
	case 9: // "MIN"
		t_out[0] = fmin(par_in[p1_A + 0], par_in[p2_B + 0]);
		t_out[1] = fmin(par_in[p1_A + 1], par_in[p2_B + 1]);
		t_out[2] = fmin(par_in[p1_A + 2], par_in[p2_B + 2]);
		t_out[3] = fmin(par_in[p1_A + 3], par_in[p2_B + 3]);
		break;
	case 10: // "MAX"
		t_out[0] = fmax(par_in[p1_A + 0], par_in[p2_B + 0]);
		t_out[1] = fmax(par_in[p1_A + 1], par_in[p2_B + 1]);
		t_out[2] = fmax(par_in[p1_A + 2], par_in[p2_B + 2]);
		t_out[3] = fmax(par_in[p1_A + 3], par_in[p2_B + 3]);
		break;
	case 11: // "SLT"
		t_out[0] = (par_in[p1_A + 0] < par_in[p2_B + 0]) ? 1.0 : 0;
		t_out[1] = (par_in[p1_A + 1] < par_in[p2_B + 1]) ? 1.0 : 0;
		t_out[2] = (par_in[p1_A + 2] < par_in[p2_B + 2]) ? 1.0 : 0;
		t_out[3] = (par_in[p1_A + 3] < par_in[p2_B + 3]) ? 1.0 : 0;
		break;
	case 12: // "SGE"
		t_out[0] = (par_in[p1_A + 0] >= par_in[p2_B + 0]) ? 1.0 : 0;
		t_out[1] = (par_in[p1_A + 1] >= par_in[p2_B + 1]) ? 1.0 : 0;
		t_out[2] = (par_in[p1_A + 2] >= par_in[p2_B + 2]) ? 1.0 : 0;
		t_out[3] = (par_in[p1_A + 3] >= par_in[p2_B + 3]) ? 1.0 : 0;
		break;
	case 13: // "ARL"
		t_out[0] = par_in[p1_A + 0];
	}
}

void vertex_program_simulator::compute_scalar_operation(float t_out[4], int instruction, float par_in[3 * 4])
{
	//const int p1_A = 0;
	//const int p2_B = 4;
	const int p3_C = 8;
	union {
		float f;
		unsigned int i;
	} t;
	int e;

	// t_out <= instruction(par_in)
	switch (instruction) {
	case 0: // "NOP"
		break;
	case 1: // "IMV"
		t_out[0] = par_in[p3_C + 0];
		t_out[1] = par_in[p3_C + 1];
		t_out[2] = par_in[p3_C + 2];
		t_out[3] = par_in[p3_C + 3];
		break;
	case 2: // "RCP"
		t_out[0] = t_out[1] = t_out[2] = t_out[3] = 1.0f / par_in[p3_C + 0];
		break;
	case 3: // "RCC"
		t_out[0] = t_out[1] = t_out[2] = t_out[3] = 1.0f / par_in[p3_C + 0]; // ?
		break;
	case 4: // "RSQ"
		/*
		 *  NOTE: this was abs which is "int abs(int x)" - and changed to fabsf due to clang 3.6 warning
		 */
		t_out[0] = t_out[1] = t_out[2] = t_out[3] = 1.0f / sqrtf(fabsf(par_in[p3_C + 0]));
		break;
	case 5: // "EXP"
		t_out[0] = pow(2, floor(par_in[p3_C + 0]));
		t_out[1] = par_in[p3_C + 0] - floorf(par_in[p3_C + 0]);
		t.f = pow(2, par_in[p3_C + 0]);
		t.i = t.i & 0xffffff00;
		t_out[2] = t.f;
		t_out[3] = 1.0;
		break;
	case 6: // "LOG"
		t_out[1] = frexp(par_in[p3_C + 0], &e)*2.0; // frexp gives mantissa as 0.5....1
		t_out[0] = e - 1;
#ifndef __OS2__
		/*
		 *  NOTE: this was abs which is "int abs(int x)" - and changed to fabsf due to clang 3.6 warning
		 */
		t.f = log2(fabsf(par_in[p3_C + 0]));
#else
		static double log_2 = 0.0;
		if (log_2 == 0.0)
			log_2 = log(2);
		t.f = log(abs(par_in[p3_C + 0])) / log_2;
#endif
		t.i = t.i & 0xffffff00;
		t_out[2] = t.f;
		t_out[3] = 1.0;
		break;
	case 7: // "LIT"
		t_out[0] = 1.0;
		t_out[1] = fmax(0, fmin(par_in[p3_C + 0], 1.0f));
		t_out[2] = par_in[p3_C + 0] > 0 ? pow(fmax(par_in[p3_C + 1], 0), par_in[p3_C + 3]) : 0;
		t_out[3] = 1.0;
		break;
	}
}

/*
 * Graphics
 */

uint32_t nv2a_renderer::dilate0(uint32_t value, int bits) // dilate first "bits" bits in "value"
{
	uint32_t x, m1, m2, m3;
	int a;

	x = value;
	for (a = 0; a < bits; a++)
	{
		m2 = 1 << (a << 1);
		m1 = m2 - 1;
		m3 = (~m1) << 1;
		x = (x & m1) + (x & m2) + ((x & m3) << 1);
	}
	return x;
}

uint32_t nv2a_renderer::dilate1(uint32_t value, int bits) // dilate first "bits" bits in "value"
{
	uint32_t x, m1, m2, m3;
	int a;

	x = value;
	for (a = 0; a < bits; a++)
	{
		m2 = 1 << (a << 1);
		m1 = m2 - 1;
		m3 = (~m1) << 1;
		x = (x & m1) + ((x & m2) << 1) + ((x & m3) << 1);
	}
	return x;
}

void nv2a_renderer::computedilated(void)
{
	int a, b;

	for (b = 0; b < 16; b++)
		for (a = 0; a < 2048; a++) {
			dilated0[b][a] = dilate0(a, b);
			dilated1[b][a] = dilate1(a, b);
		}
	for (b = 0; b < 16; b++)
		for (a = 0; a < 16; a++)
			dilatechose[(b << 4) + a] = (a < b ? a : b);
}

inline uint8_t *nv2a_renderer::direct_access_ptr(offs_t address)
{
#ifdef DEBUG_CHECKS
	if (address >= 512*1024*1024)
		machine().logerror("Bad address in direct_access_ptr !\n");
#endif
	return basemempointer + address;
}

int nv2a_renderer::geforce_commandkind(uint32_t word)
{
	if ((word & 0x00000003) == 0x00000002)
		return 7; // call
	if ((word & 0x00000003) == 0x00000001)
		return 6; // jump
	if ((word & 0xE0030003) == 0x40000000)
		return 5; // non increasing
	if ((word & 0xE0000003) == 0x20000000)
		return 4; // old jump
	if ((word & 0xFFFF0003) == 0x00030000)
		return 3; // long non icreasing
	if ((word & 0xFFFFFFFF) == 0x00020000)
		return 2; // return
	if ((word & 0xFFFF0003) == 0x00010000)
		return 1; // sli conditional
	if ((word & 0xE0030003) == 0x00000000)
		return 0; // increasing
	return -1;
}

uint32_t nv2a_renderer::geforce_object_offset(uint32_t handle)
{
	uint32_t h = ((((handle >> 11) ^ handle) >> 11) ^ handle) & 0x7ff;
	uint32_t o = (pfifo[0x210 / 4] & 0x1ff) << 8; // 0x1ff is not certain
	uint32_t e = o + h * 8; // at 0xfd000000+0x00700000
	uint32_t w;

	if (ramin[e / 4] != handle) {
		// this should never happen
		for (uint32_t aa = o / 4; aa < (sizeof(ramin) / 4); aa = aa + 2) {
			if (ramin[aa] == handle) {
				e = aa * 4;
			}
		}
	}
	w = ramin[e / 4 + 1];
	return (w & 0xffff) * 0x10; // 0xffff is not certain
}

void nv2a_renderer::geforce_read_dma_object(uint32_t handle, uint32_t &offset, uint32_t &size)
{
	//uint32_t objclass,pt_present,pt_linear,access,target,rorw;
	uint32_t dma_adjust, dma_frame;
	uint32_t o = geforce_object_offset(handle);

	o = o / 4;
	//objclass=ramin[o] & 0xfff;
	//pt_present=(ramin[o] >> 12) & 1;
	//pt_linear=(ramin[o] >> 13) & 1;
	//access=(ramin[o] >> 14) & 3;
	//target=(ramin[o] >> 16) & 3;
	dma_adjust = (ramin[o] >> 20) & 0xfff;
	size = ramin[o + 1];
	//rorw=ramin[o+2] & 1;
	dma_frame = ramin[o + 2] & 0xfffff000;
	offset = dma_frame + dma_adjust;
}

/*void myline(bitmap_rgb32 &bmp,float x1,float y1,float x2,float y2)
{
int xx1,yy1,xx2,yy2;

    xx1=x1;
    xx2=x2;
    yy1=y1;
    yy2=y2;
    if (xx1 == xx2) {
        if (yy1 > yy2) {
            int t=yy1;
            yy1=yy2;
            yy2=t;
        }
        for (int y=yy1;y <= yy2;y++)
            *((uint32_t *)bmp.raw_pixptr(y,xx1))= -1;
        } else if (yy1 == yy2) {
        if (xx1 > xx2) {
            int t=xx1;
            xx1=xx2;
            xx2=t;
        }
        for (int x=xx1;x <= xx2;x++)
            *((uint32_t *)bmp.raw_pixptr(yy1,x))= -1;
    }
}*/

inline uint32_t convert_a4r4g4b4_a8r8g8b8(uint32_t a4r4g4b4)
{
	uint32_t a8r8g8b8;
	int ca, cr, cg, cb;

	cb = pal4bit(a4r4g4b4 & 0x000f);
	cg = pal4bit((a4r4g4b4 & 0x00f0) >> 4);
	cr = pal4bit((a4r4g4b4 & 0x0f00) >> 8);
	ca = pal4bit((a4r4g4b4 & 0xf000) >> 12);
	a8r8g8b8 = (ca << 24) | (cr << 16) | (cg << 8) | (cb); // color converted to 8 bits per component
	return a8r8g8b8;
}

inline uint32_t convert_a1r5g5b5_a8r8g8b8(uint32_t a1r5g5b5)
{
	uint32_t a8r8g8b8;
	int ca, cr, cg, cb;

	cb = pal5bit(a1r5g5b5 & 0x001f);
	cg = pal5bit((a1r5g5b5 & 0x03e0) >> 5);
	cr = pal5bit((a1r5g5b5 & 0x7c00) >> 10);
	ca = a1r5g5b5 & 0x8000 ? 0xff : 0;
	a8r8g8b8 = (ca << 24) | (cr << 16) | (cg << 8) | (cb); // color converted to 8 bits per component
	return a8r8g8b8;
}

inline uint32_t convert_r5g6b5_r8g8b8(uint32_t r5g6b5)
{
	uint32_t r8g8b8;
	int cr, cg, cb;

	cb = pal5bit(r5g6b5 & 0x001f);
	cg = pal6bit((r5g6b5 & 0x07e0) >> 5);
	cr = pal5bit((r5g6b5 & 0xf800) >> 11);
	r8g8b8 = (cr << 16) | (cg << 8) | (cb); // color converted to 8 bits per component
	return r8g8b8;
}

uint32_t nv2a_renderer::texture_get_texel(int number, int x, int y)
{
	uint32_t to, s, c, sa, ca;
	uint32_t a4r4g4b4, a1r5g5b5, r5g6b5;
	int bx, by;
	int color0, color1, color0m2, color1m2, alpha0, alpha1;
	uint32_t codes;
	uint64_t alphas;
	int cr, cg, cb;
	int sizeu, sizev;

	// force to [0,size-1]
	if (texture[number].rectangle == false) {
		sizeu = texture[number].sizeu;
		sizev = texture[number].sizev;
		x = (unsigned int)x & (sizeu - 1);
		y = (unsigned int)y & (sizev - 1);
	} else
	{
		sizeu = texture[number].rectwidth;
		sizev = texture[number].rectheight;
		x = x % sizeu;
		if (x < 0)
			x = sizeu + x;
		y = y % sizev;
		if (y < 0)
			y = sizev + y;
	}
	switch (texture[number].format) {
	case NV2A_TEX_FORMAT::A8R8G8B8:
		to = dilated0[texture[number].dilate][x] + dilated1[texture[number].dilate][y]; // offset of texel in texture memory
		return *(((uint32_t *)texture[number].buffer) + to); // get texel color
	case NV2A_TEX_FORMAT::DXT1:
		bx = x >> 2;
		by = y >> 2;
		x = x & 3;
		y = y & 3;
		to = bx + by*(sizeu >> 2);
		color0 = *((uint16_t *)(((uint64_t *)texture[number].buffer) + to) + 0);
		color1 = *((uint16_t *)(((uint64_t *)texture[number].buffer) + to) + 1);
		codes = *((uint32_t *)(((uint64_t *)texture[number].buffer) + to) + 1);
		s = (y << 3) + (x << 1);
		c = (codes >> s) & 3;
		c = c + (color0 > color1 ? 0 : 4);
		color0m2 = color0 << 1;
		color1m2 = color1 << 1;
		switch (c) {
		case 0:
			return 0xff000000 + convert_r5g6b5_r8g8b8(color0);
		case 1:
			return 0xff000000 + convert_r5g6b5_r8g8b8(color1);
		case 2:
			cb = pal5bit(((color0m2 & 0x003e) + (color1 & 0x001f)) / 3);
			cg = pal6bit(((color0m2 & 0x0fc0) + (color1 & 0x07e0)) / 3 >> 5);
			cr = pal5bit(((color0m2 & 0x1f000) + color1) / 3 >> 11);
			return 0xff000000 | (cr << 16) | (cg << 8) | (cb);
		case 3:
			cb = pal5bit(((color1m2 & 0x003e) + (color0 & 0x001f)) / 3);
			cg = pal6bit(((color1m2 & 0x0fc0) + (color0 & 0x07e0)) / 3 >> 5);
			cr = pal5bit(((color1m2 & 0x1f000) + color0) / 3 >> 11);
			return 0xff000000 | (cr << 16) | (cg << 8) | (cb);
		case 4:
			return 0xff000000 + convert_r5g6b5_r8g8b8(color0);
		case 5:
			return 0xff000000 + convert_r5g6b5_r8g8b8(color1);
		case 6:
			cb = pal5bit(((color0 & 0x001f) + (color1 & 0x001f)) / 2);
			cg = pal6bit(((color0 & 0x07e0) + (color1 & 0x07e0)) / 2 >> 5);
			cr = pal5bit(((color0 & 0xf800) + (color1 & 0xf800)) / 2 >> 11);
			return 0xff000000 | (cr << 16) | (cg << 8) | (cb);
		default:
			return 0xff000000;
		}
	case NV2A_TEX_FORMAT::DXT3:
		bx = x >> 2;
		by = y >> 2;
		x = x & 3;
		y = y & 3;
		to = (bx + by*(sizeu >> 2)) << 1;
		color0 = *((uint16_t *)(((uint64_t *)texture[number].buffer) + to) + 4);
		color1 = *((uint16_t *)(((uint64_t *)texture[number].buffer) + to) + 5);
		codes = *((uint32_t *)(((uint64_t *)texture[number].buffer) + to) + 3);
		alphas = *(((uint64_t *)texture[number].buffer) + to);
		s = (y << 3) + (x << 1);
		sa = ((y << 2) + x) << 2;
		c = (codes >> s) & 3;
		ca = (alphas >> sa) & 15;
		switch (c) {
		case 0:
			return ((ca + (ca << 4)) << 24) + convert_r5g6b5_r8g8b8(color0);
		case 1:
			return ((ca + (ca << 4)) << 24) + convert_r5g6b5_r8g8b8(color1);
		case 2:
			cb = pal5bit((2 * (color0 & 0x001f) + (color1 & 0x001f)) / 3);
			cg = pal6bit((2 * (color0 & 0x07e0) + (color1 & 0x07e0)) / 3 >> 5);
			cr = pal5bit((2 * (color0 & 0xf800) + (color1 & 0xf800)) / 3 >> 11);
			return ((ca + (ca << 4)) << 24) | (cr << 16) | (cg << 8) | (cb);
		default:
			cb = pal5bit(((color0 & 0x001f) + 2 * (color1 & 0x001f)) / 3);
			cg = pal6bit(((color0 & 0x07e0) + 2 * (color1 & 0x07e0)) / 3 >> 5);
			cr = pal5bit(((color0 & 0xf800) + 2 * (color1 & 0xf800)) / 3 >> 11);
			return ((ca + (ca << 4)) << 24) | (cr << 16) | (cg << 8) | (cb);
		}
	case NV2A_TEX_FORMAT::A4R4G4B4:
		to = dilated0[texture[number].dilate][x] + dilated1[texture[number].dilate][y]; // offset of texel in texture memory
		a4r4g4b4 = *(((uint16_t *)texture[number].buffer) + to); // get texel color
		return convert_a4r4g4b4_a8r8g8b8(a4r4g4b4);
	case NV2A_TEX_FORMAT::A1R5G5B5:
		to = dilated0[texture[number].dilate][x] + dilated1[texture[number].dilate][y]; // offset of texel in texture memory
		a1r5g5b5 = *(((uint16_t *)texture[number].buffer) + to); // get texel color
		return convert_a1r5g5b5_a8r8g8b8(a1r5g5b5);
	case NV2A_TEX_FORMAT::R5G6B5:
		to = dilated0[texture[number].dilate][x] + dilated1[texture[number].dilate][y]; // offset of texel in texture memory
		r5g6b5 = *(((uint16_t *)texture[number].buffer) + to); // get texel color
		return 0xff000000 + convert_r5g6b5_r8g8b8(r5g6b5);
	case NV2A_TEX_FORMAT::R8G8B8_RECT:
		to = texture[number].rectangle_pitch*y + (x << 2);
		return *((uint32_t *)(((uint8_t *)texture[number].buffer) + to));
	case NV2A_TEX_FORMAT::A8R8G8B8_RECT:
		to = texture[number].rectangle_pitch*y + (x << 2);
		return *((uint32_t *)(((uint8_t *)texture[number].buffer) + to));
	case NV2A_TEX_FORMAT::DXT5:
		bx = x >> 2;
		by = y >> 2;
		x = x & 3;
		y = y & 3;
		to = (bx + by*(sizeu >> 2)) << 1;
		color0 = *((uint16_t *)(((uint64_t *)texture[number].buffer) + to) + 4);
		color1 = *((uint16_t *)(((uint64_t *)texture[number].buffer) + to) + 5);
		codes = *((uint32_t *)(((uint64_t *)texture[number].buffer) + to) + 3);
		alpha0 = *((uint8_t *)(((uint64_t *)texture[number].buffer) + to) + 0);
		alpha1 = *((uint8_t *)(((uint64_t *)texture[number].buffer) + to) + 1);
		alphas = *(((uint64_t *)texture[number].buffer) + to);
		s = (y << 3) + (x << 1);
		sa = ((y << 2) + x) * 3;
		c = (codes >> s) & 3;
		ca = (alphas >> sa) & 7;
		ca = ca + (alpha0 > alpha1 ? 0 : 8);
		switch (ca) {
		case 0:
			ca = alpha0;
			break;
		case 1:
			ca = alpha1;
			break;
		case 2:
			ca = (6 * alpha0 + 1 * alpha1) / 7;
			break;
		case 3:
			ca = (5 * alpha0 + 2 * alpha1) / 7;
			break;
		case 4:
			ca = (4 * alpha0 + 3 * alpha1) / 7;
			break;
		case 5:
			ca = (3 * alpha0 + 4 * alpha1) / 7;
			break;
		case 6:
			ca = (2 * alpha0 + 5 * alpha1) / 7;
			break;
		case 7:
			ca = (1 * alpha0 + 6 * alpha1) / 7;
			break;
		case 8:
			ca = alpha0;
			break;
		case 9:
			ca = alpha1;
			break;
		case 10:
			ca = (4 * alpha0 + 1 * alpha1) / 5;
			break;
		case 11:
			ca = (3 * alpha0 + 2 * alpha1) / 5;
			break;
		case 12:
			ca = (2 * alpha0 + 3 * alpha1) / 5;
			break;
		case 13:
			ca = (1 * alpha0 + 4 * alpha1) / 5;
			break;
		case 14:
			ca = 0;
			break;
		case 15:
			ca = 255;
			break;
		}
		switch (c) {
		case 0:
			return (ca << 24) + convert_r5g6b5_r8g8b8(color0);
		case 1:
			return (ca << 24) + convert_r5g6b5_r8g8b8(color1);
		case 2:
			cb = pal5bit((2 * (color0 & 0x001f) + (color1 & 0x001f)) / 3);
			cg = pal6bit((2 * (color0 & 0x07e0) + (color1 & 0x07e0)) / 3 >> 5);
			cr = pal5bit((2 * (color0 & 0xf800) + (color1 & 0xf800)) / 3 >> 11);
			return (ca << 24) | (cr << 16) | (cg << 8) | (cb);
		default:
			cb = pal5bit(((color0 & 0x001f) + 2 * (color1 & 0x001f)) / 3);
			cg = pal6bit(((color0 & 0x07e0) + 2 * (color1 & 0x07e0)) / 3 >> 5);
			cr = pal5bit(((color0 & 0xf800) + 2 * (color1 & 0xf800)) / 3 >> 11);
			return (ca << 24) | (cr << 16) | (cg << 8) | (cb);
		}
	default:
		return 0xff00ff00;
	}
}

inline uint8_t *nv2a_renderer::read_pixel(int x, int y, int32_t c[4])
{
	uint32_t offset;
	uint32_t color;
	uint32_t *addr;
	uint16_t *addr16;
	uint8_t *addr8;

	if (type_rendertarget == NV2A_RT_TYPE::SWIZZLED)
		offset = (dilated0[dilate_rendertarget][x] + dilated1[dilate_rendertarget][y]) * bytespixel_rendertarget;
	else // type_rendertarget == LINEAR
		offset = pitch_rendertarget * y + x * bytespixel_rendertarget;
#ifdef DEBUG_CHECKS
	if (offset >= size_rendertarget)
	{
		machine().logerror("Bad offset computed in read_pixel !\n");
		offset = 0;
	}
#endif
	switch (colorformat_rendertarget) {
	case NV2A_COLOR_FORMAT::R5G6B5:
		addr16 = (uint16_t *)((uint8_t *)rendertarget + offset);
		color = *addr16;
		c[3] = 0xff;
		c[2] = pal5bit((color & 0xf800) >> 11);
		c[1] = pal6bit((color & 0x07e0) >> 5);
		c[0] = pal5bit(color & 0x1f);
		return (uint8_t *)addr16;
	case NV2A_COLOR_FORMAT::X8R8G8B8_Z8R8G8B8:
	case NV2A_COLOR_FORMAT::X8R8G8B8_X8R8G8B8:
		addr = (uint32_t *)((uint8_t *)rendertarget + offset);
		color = *addr;

		c[3] = 0xff;
		c[2] = (color >> 16) & 255;
		c[1] = (color >> 8) & 255;
		c[0] = color & 255;
		return (uint8_t *)addr;
	case NV2A_COLOR_FORMAT::A8R8G8B8:
		addr = (uint32_t *)((uint8_t *)rendertarget + offset);
		color = *addr;
		c[3] = color >> 24;
		c[2] = (color >> 16) & 255;
		c[1] = (color >> 8) & 255;
		c[0] = color & 255;
		return (uint8_t *)addr;
	case NV2A_COLOR_FORMAT::B8:
		addr8 = (uint8_t *)rendertarget + offset;
		c[0] = *addr8;
		c[1] = c[2] = 0;
		c[3] = 0xff;
		return addr8;
	default:
		return nullptr;
	}
	return nullptr;
}

void nv2a_renderer::write_pixel(int x, int y, uint32_t color, int depth)
{
	uint8_t *addr;
	uint32_t *daddr32;
	uint16_t *daddr16;
	uint32_t deptsten;
	int32_t c[4], fb[4], s[4], d[4], cc[4];
	uint32_t dep, sten, stenc, stenv;
	bool stencil_passed;
	bool depth_passed;

	if ((depth > 0xffffff) || (depth < 0) || (x < 0))
		return;
	fb[3] = fb[2] = fb[1] = fb[0] = 0;
	addr = nullptr;
	if (color_mask != 0)
		addr = read_pixel(x, y, fb);
	if (depthformat_rendertarget == NV2A_RT_DEPTH_FORMAT::Z24S8) {
#ifdef DEBUG_CHECKS
		if (((pitch_depthbuffer / 4) * y + x) >= size_depthbuffer)
		{
			machine().logerror("Bad depthbuffer offset computed in write_pixel !\n");
			return;
		}
#endif
		daddr32 = depthbuffer + (pitch_depthbuffer / 4) * y + x;
		deptsten = *daddr32;
		dep = deptsten >> 8;
		sten = deptsten & 255;
		daddr16 = nullptr;
	}
	else if (depthformat_rendertarget == NV2A_RT_DEPTH_FORMAT::Z16) {
#ifdef DEBUG_CHECKS
		if (((pitch_depthbuffer / 2) * y + x) >= size_depthbuffer)
		{
			machine().logerror("Bad depthbuffer offset computed in write_pixel !\n");
			return;
		}
#endif
		daddr16 = (uint16_t *)depthbuffer + (pitch_depthbuffer / 2) * y + x;
		deptsten = *daddr16;
		dep = (deptsten << 8) | 0xff;
		sten = 0;
		daddr32 = nullptr;
	}
	else {
		daddr32 = nullptr;
		daddr16 = nullptr;
		dep = 0xffffff;
		sten = 0;
	}
	c[3] = color >> 24;
	c[2] = (color >> 16) & 255;
	c[1] = (color >> 8) & 255;
	c[0] = color & 255;
	cc[3] = blend_color >> 24;
	cc[2] = (blend_color >> 16) & 255;
	cc[1] = (blend_color >> 8) & 255;
	cc[0] = blend_color & 255;
	// ownership test and scissor test not done
	// alpha test
	if (alpha_test_enabled) {
		switch (alpha_func) {
			case NV2A_COMPARISON_OP::NEVER:
				return;
			case NV2A_COMPARISON_OP::ALWAYS:
			default:
				break;
			case NV2A_COMPARISON_OP::LESS:
				if (c[3] >= alpha_reference)
					return;
				break;
			case NV2A_COMPARISON_OP::LEQUAL:
				if (c[3] > alpha_reference)
					return;
				break;
			case NV2A_COMPARISON_OP::EQUAL:
				if (c[3] != alpha_reference)
					return;
				break;
			case NV2A_COMPARISON_OP::GEQUAL:
				if (c[3] < alpha_reference)
					return;
				break;
			case NV2A_COMPARISON_OP::GREATER:
				if (c[3] <= alpha_reference)
					return;
				break;
			case NV2A_COMPARISON_OP::NOTEQUAL:
				if (c[3] == alpha_reference)
					return;
				break;
		}
	}
	// stencil test
	stencil_passed = true;
	if (stencil_test_enabled) {
		stenc=stencil_mask & stencil_ref;
		stenv=stencil_mask & sten;
		switch (stencil_func) {
		case NV2A_COMPARISON_OP::NEVER:
			stencil_passed = false;
			break;
		case NV2A_COMPARISON_OP::LESS:
			if (stenc >= stenv)
				stencil_passed = false;
			break;
		case NV2A_COMPARISON_OP::EQUAL:
			if (stenc != stenv)
				stencil_passed = false;
			break;
		case NV2A_COMPARISON_OP::LEQUAL:
			if (stenc > stenv)
				stencil_passed = false;
			break;
		case NV2A_COMPARISON_OP::GREATER:
			if (stenc <= stenv)
				stencil_passed = false;
			break;
		case NV2A_COMPARISON_OP::NOTEQUAL:
			if (stenc == stenv)
				stencil_passed = false;
			break;
		case NV2A_COMPARISON_OP::GEQUAL:
			if (stenc < stenv)
				stencil_passed = false;
			break;
		case NV2A_COMPARISON_OP::ALWAYS:
		default:
			break;
		}
		if (stencil_passed == false) {
			switch (stencil_op_fail) {
			case NV2A_STENCIL_OP::ZEROOP:
				sten = 0;
				break;
			case NV2A_STENCIL_OP::INVERTOP:
				sten = sten ^ 255;
				break;
			case NV2A_STENCIL_OP::KEEP:
			default:
				break;
			case NV2A_STENCIL_OP::REPLACE:
				sten = stencil_ref;
				break;
			case NV2A_STENCIL_OP::INCR:
				if (sten < 255)
					sten++;
				break;
			case NV2A_STENCIL_OP::DECR:
				if (sten > 0)
					sten--;
				break;
			case NV2A_STENCIL_OP::INCR_WRAP:
				if (sten < 255)
					sten++;
				else
					sten = 0;
				break;
			case NV2A_STENCIL_OP::DECR_WRAP:
				if (sten > 0)
					sten--;
				else
					sten = 255;
				break;
			}
			if (depthformat_rendertarget == NV2A_RT_DEPTH_FORMAT::Z24S8) {
				deptsten = (dep << 8) | sten;
				*daddr32 = deptsten;
			}
			else if (depthformat_rendertarget == NV2A_RT_DEPTH_FORMAT::Z16) {
				deptsten = dep >> 8;
				*daddr16 = (uint16_t)deptsten;
			}
			return;
		}
	}
	// depth buffer test
	depth_passed = true;
	if (depth_test_enabled) {
		switch (depth_function) {
			case NV2A_COMPARISON_OP::NEVER:
				depth_passed = false;
				break;
			case NV2A_COMPARISON_OP::LESS:
				if (depth >= dep)
					depth_passed = false;
				break;
			case NV2A_COMPARISON_OP::EQUAL:
				if (depth != dep)
					depth_passed = false;
				break;
			case NV2A_COMPARISON_OP::LEQUAL:
				if (depth > dep)
					depth_passed = false;
				break;
			case NV2A_COMPARISON_OP::GREATER:
				if (depth <= dep)
					depth_passed = false;
				break;
			case NV2A_COMPARISON_OP::NOTEQUAL:
				if (depth == dep)
					depth_passed = false;
				break;
			case NV2A_COMPARISON_OP::GEQUAL:
				if (depth < dep)
					depth_passed = false;
				break;
			case NV2A_COMPARISON_OP::ALWAYS:
			default:
				break;
		}
		if (depth_passed == false) {
			switch (stencil_op_zfail) {
			case NV2A_STENCIL_OP::ZEROOP:
				sten = 0;
				break;
			case NV2A_STENCIL_OP::INVERTOP:
				sten = sten ^ 255;
				break;
			case NV2A_STENCIL_OP::KEEP:
			default:
				break;
			case NV2A_STENCIL_OP::REPLACE:
				sten = stencil_ref;
				break;
			case NV2A_STENCIL_OP::INCR:
				if (sten < 255)
					sten++;
				break;
			case NV2A_STENCIL_OP::DECR:
				if (sten > 0)
					sten--;
				break;
			case NV2A_STENCIL_OP::INCR_WRAP:
				if (sten < 255)
					sten++;
				else
					sten = 0;
				break;
			case NV2A_STENCIL_OP::DECR_WRAP:
				if (sten > 0)
					sten--;
				else
					sten = 255;
				break;
			}
			if (depthformat_rendertarget == NV2A_RT_DEPTH_FORMAT::Z24S8) {
				deptsten = (dep << 8) | sten;
				*daddr32 = deptsten;
			}
			else if (depthformat_rendertarget == NV2A_RT_DEPTH_FORMAT::Z16) {
				deptsten = dep >> 8;
				*daddr16 = (uint16_t)deptsten;
			}
			return;
		}
		switch (stencil_op_zpass) {
		case NV2A_STENCIL_OP::ZEROOP:
			sten = 0;
			break;
		case NV2A_STENCIL_OP::INVERTOP:
			sten = sten ^ 255;
			break;
		case NV2A_STENCIL_OP::KEEP:
		default:
			break;
		case NV2A_STENCIL_OP::REPLACE:
			sten = stencil_ref;
			break;
		case NV2A_STENCIL_OP::INCR:
			if (sten < 255)
				sten++;
			break;
		case NV2A_STENCIL_OP::DECR:
			if (sten > 0)
				sten--;
			break;
		case NV2A_STENCIL_OP::INCR_WRAP:
			if (sten < 255)
				sten++;
			else
				sten = 0;
			break;
		case NV2A_STENCIL_OP::DECR_WRAP:
			if (sten > 0)
				sten--;
			else
				sten = 255;
			break;
		}
	}
	// blending
	if (blending_enabled) {
		switch (blend_function_source) {
			case NV2A_BLEND_FACTOR::ZERO:
				s[3] = s[2] = s[1] = s[0] = 0;
				break;
			case NV2A_BLEND_FACTOR::ONE:
			default:
				s[3] = s[2] = s[1] = s[0] = 255;
				break;
			case NV2A_BLEND_FACTOR::DST_COLOR:
				s[3] = fb[3];
				s[2] = fb[2];
				s[1] = fb[1];
				s[0] = fb[0];
				break;
			case NV2A_BLEND_FACTOR::ONE_MINUS_DST_COLOR:
				s[3] = fb[3] ^ 255;
				s[2] = fb[2] ^ 255;
				s[1] = fb[1] ^ 255;
				s[0] = fb[0] ^ 255;
				break;
			case NV2A_BLEND_FACTOR::SRC_ALPHA:
				s[3] = s[2] = s[1] = s[0] = c[3];
				break;
			case NV2A_BLEND_FACTOR::ONE_MINUS_SRC_ALPHA:
				s[3] = s[2] = s[1] = s[0] = c[3] ^ 255;
				break;
			case NV2A_BLEND_FACTOR::DST_ALPHA:
				s[3] = s[2] = s[1] = s[0] = fb[3];
				break;
			case NV2A_BLEND_FACTOR::ONE_MINUS_DST_ALPHA:
				s[3] = s[2] = s[1] = s[0] = fb[3] ^ 255;
				break;
			case NV2A_BLEND_FACTOR::CONSTANT_COLOR:
				s[3] = cc[3];
				s[2] = cc[2];
				s[1] = cc[1];
				s[0] = cc[0];
				break;
			case NV2A_BLEND_FACTOR::ONE_MINUS_CONSTANT_COLOR:
				s[3] = cc[3] ^ 255;
				s[2] = cc[2] ^ 255;
				s[1] = cc[1] ^ 255;
				s[0] = cc[0] ^ 255;
				break;
			case NV2A_BLEND_FACTOR::CONSTANT_ALPHA:
				s[3] = s[2] = s[1] = s[0] = cc[3];
				break;
			case NV2A_BLEND_FACTOR::ONE_MINUS_CONSTANT_ALPHA:
				s[3] = s[2] = s[1] = s[0] = cc[3] ^ 255;
				break;
			case NV2A_BLEND_FACTOR::SRC_ALPHA_SATURATE:
				s[3] = 255;
				if (c[3] < (fb[3] ^ 255))
					s[2] = c[3];
				else
					s[2] = fb[3];
				s[1] = s[0] = s[2];
				break;
		}
		switch (blend_function_destination) {
			case NV2A_BLEND_FACTOR::ZERO:
			default:
				d[3] = d[2] = d[1] = d[0] = 0;
				break;
			case NV2A_BLEND_FACTOR::ONE:
				d[3] = d[2] = d[1] = d[0] = 255;
				break;
			case NV2A_BLEND_FACTOR::SRC_COLOR:
				d[3] = c[3];
				d[2] = c[2];
				d[1] = c[1];
				d[0] = c[0];
				break;
			case NV2A_BLEND_FACTOR::ONE_MINUS_SRC_COLOR:
				d[3] = c[3] ^ 255;
				d[2] = c[2] ^ 255;
				d[1] = c[1] ^ 255;
				d[0] = c[0] ^ 255;
				break;
			case NV2A_BLEND_FACTOR::SRC_ALPHA:
				d[3] = d[2] = d[1] = d[0] = c[3];
				break;
			case NV2A_BLEND_FACTOR::ONE_MINUS_SRC_ALPHA:
				d[3] = d[2] = d[1] = d[0] = c[3] ^ 255;
				break;
			case NV2A_BLEND_FACTOR::DST_ALPHA:
				d[3] = d[2] = d[1] = d[0] = fb[3];
				break;
			case NV2A_BLEND_FACTOR::ONE_MINUS_DST_ALPHA:
				d[3] = d[2] = d[1] = d[0] = fb[3] ^ 255;
				break;
			case NV2A_BLEND_FACTOR::CONSTANT_COLOR:
				d[3] = cc[3];
				d[2] = cc[2];
				d[1] = cc[1];
				d[0] = cc[0];
				break;
			case NV2A_BLEND_FACTOR::ONE_MINUS_CONSTANT_COLOR:
				d[3] = cc[3] ^ 255;
				d[2] = cc[2] ^ 255;
				d[1] = cc[1] ^ 255;
				d[0] = cc[0] ^ 255;
				break;
			case NV2A_BLEND_FACTOR::CONSTANT_ALPHA:
				d[3] = d[2] = d[1] = d[0] = cc[3];
				break;
			case NV2A_BLEND_FACTOR::ONE_MINUS_CONSTANT_ALPHA:
				d[3] = d[2] = d[1] = d[0] = cc[3] ^ 255;
				break;
		}
		switch (blend_equation) {
			case NV2A_BLEND_EQUATION::FUNC_ADD:
				c[3] = (c[3] * s[3] + fb[3] * d[3]) / 255;
				if (c[3] > 255)
					c[3] = 255;
				c[2] = (c[2] * s[2] + fb[2] * d[2]) / 255;
				if (c[2] > 255)
					c[2] = 255;
				c[1] = (c[1] * s[1] + fb[1] * d[1]) / 255;
				if (c[1] > 255)
					c[1] = 255;
				c[0] = (c[0] * s[0] + fb[0] * d[0]) / 255;
				if (c[0] > 255)
					c[0] = 255;
				break;
			case NV2A_BLEND_EQUATION::FUNC_SUBTRACT:
				c[3] = (c[3] * s[3] - fb[3] * d[3]) / 255;
				if (c[3] < 0)
					c[3] = 255;
				c[2] = (c[2] * s[2] - fb[2] * d[2]) / 255;
				if (c[2] < 0)
					c[2] = 255;
				c[1] = (c[1] * s[1] - fb[1] * d[1]) / 255;
				if (c[1] < 0)
					c[1] = 255;
				c[0] = (c[0] * s[0] - fb[0] * d[0]) / 255;
				if (c[0] < 0)
					c[0] = 255;
				break;
			case NV2A_BLEND_EQUATION::FUNC_REVERSE_SUBTRACT:
				c[3] = (fb[3] * d[3] - c[3] * s[3]) / 255;
				if (c[3] < 0)
					c[3] = 255;
				c[2] = (fb[2] * d[2] - c[2] * s[2]) / 255;
				if (c[2] < 0)
					c[2] = 255;
				c[1] = (fb[1] * d[1] - c[1] * s[1]) / 255;
				if (c[1] < 0)
					c[1] = 255;
				c[0] = (fb[0] * d[0] - c[0] * s[0]) / 255;
				if (c[0] < 0)
					c[0] = 255;
				break;
			case NV2A_BLEND_EQUATION::MIN:
				c[3] = s[3];
				if (d[3] < c[3])
					c[3] = d[3];
				c[2] = s[2];
				if (d[2] < c[2])
					c[2] = d[2];
				c[1] = s[1];
				if (d[1] < c[1])
					c[1] = d[1];
				c[0] = s[0];
				if (d[0] < c[0])
					c[0] = d[0];
				break;
			case NV2A_BLEND_EQUATION::MAX:
				c[3] = s[3];
				if (d[3] > c[3])
					c[3] = d[3];
				c[2] = s[2];
				if (d[2] > c[2])
					c[2] = d[2];
				c[1] = s[1];
				if (d[1] > c[1])
					c[1] = d[1];
				c[0] = s[0];
				if (d[0] > c[0])
					c[0] = d[0];
				break;
		}
	}
	// dithering not done
	// logical operation
	if (logical_operation_enabled) {
		switch (logical_operation) {
			case  NV2A_LOGIC_OP::CLEAR:
				c[3] = 0;
				c[2] = 0;
				c[1] = 0;
				c[0] = 0;
				break;
			case  NV2A_LOGIC_OP::AND:
				c[3] = c[3] & fb[3];
				c[2] = c[2] & fb[2];
				c[1] = c[1] & fb[1];
				c[0] = c[0] & fb[0];
				break;
			case  NV2A_LOGIC_OP::AND_REVERSE:
				c[3] = c[3] & (fb[3] ^ 255);
				c[2] = c[2] & (fb[2] ^ 255);
				c[1] = c[1] & (fb[1] ^ 255);
				c[0] = c[0] & (fb[0] ^ 255);
				break;
			case  NV2A_LOGIC_OP::COPY:
			default:
				break;
			case  NV2A_LOGIC_OP::AND_INVERTED:
				c[3] = (c[3] ^ 255) & fb[3];
				c[2] = (c[2] ^ 255) & fb[2];
				c[1] = (c[1] ^ 255) & fb[1];
				c[0] = (c[0] ^ 255) & fb[0];
				break;
			case  NV2A_LOGIC_OP::NOOP:
				c[3] = fb[3];
				c[2] = fb[2];
				c[1] = fb[1];
				c[0] = fb[0];
				break;
			case  NV2A_LOGIC_OP::XOR:
				c[3] = c[3] ^ fb[3];
				c[2] = c[2] ^ fb[2];
				c[1] = c[1] ^ fb[1];
				c[0] = c[0] ^ fb[0];
				break;
			case  NV2A_LOGIC_OP::OR:
				c[3] = c[3] | fb[3];
				c[2] = c[2] | fb[2];
				c[1] = c[1] | fb[1];
				c[0] = c[0] | fb[0];
				break;
			case  NV2A_LOGIC_OP::NOR:
				c[3] = (c[3] | fb[3]) ^ 255;
				c[2] = (c[2] | fb[2]) ^ 255;
				c[1] = (c[1] | fb[1]) ^ 255;
				c[0] = (c[0] | fb[0]) ^ 255;
				break;
			case  NV2A_LOGIC_OP::EQUIV:
				c[3] = (c[3] ^ fb[3]) ^ 255;
				c[2] = (c[2] ^ fb[2]) ^ 255;
				c[1] = (c[1] ^ fb[1]) ^ 255;
				c[0] = (c[0] ^ fb[0]) ^ 255;
				break;
			case  NV2A_LOGIC_OP::INVERT:
				c[3] = fb[3] ^ 255;
				c[2] = fb[2] ^ 255;
				c[1] = fb[1] ^ 255;
				c[0] = fb[0] ^ 255;
				break;
			case  NV2A_LOGIC_OP::OR_REVERSE:
				c[3] = c[3] | (fb[3] ^ 255);
				c[2] = c[2] | (fb[2] ^ 255);
				c[1] = c[1] | (fb[1] ^ 255);
				c[0] = c[0] | (fb[0] ^ 255);
				break;
			case  NV2A_LOGIC_OP::COPY_INVERTED:
				c[3] = c[3] ^ 255;
				c[2] = c[2] ^ 255;
				c[1] = c[1] ^ 255;
				c[0] = c[0] ^ 255;
				break;
			case  NV2A_LOGIC_OP::OR_INVERTED:
				c[3] = (c[3] ^ 255) | fb[3];
				c[2] = (c[2] ^ 255) | fb[2];
				c[1] = (c[1] ^ 255) | fb[1];
				c[0] = (c[0] ^ 255) | fb[0];
				break;
			case  NV2A_LOGIC_OP::NAND:
				c[3] = (c[3] & fb[3]) ^ 255;
				c[2] = (c[2] & fb[2]) ^ 255;
				c[1] = (c[1] & fb[1]) ^ 255;
				c[0] = (c[0] & fb[0]) ^ 255;
				break;
			case  NV2A_LOGIC_OP::SET:
				c[3] = 255;
				c[2] = 255;
				c[1] = 255;
				c[0] = 255;
				break;
		}
	}
	if (color_mask != 0) {
		uint32_t ct,ft,w;

		ct = ((uint32_t)c[3] << 24) | ((uint32_t)c[2] << 16) | ((uint32_t)c[1] << 8) | (uint32_t)c[0];
		ft = ((uint32_t)fb[3] << 24) | ((uint32_t)fb[2] << 16) | ((uint32_t)fb[1] << 8) | (uint32_t)fb[0];
		w = (ft & ~color_mask) | (ct & color_mask);
		switch (colorformat_rendertarget) {
		case NV2A_COLOR_FORMAT::R5G6B5:
			w = ((w >> 8) & 0xf800) + ((w >> 5) & 0x7e0) + ((w >> 3) & 0x1f);
			*((uint16_t *)addr) = (uint16_t)w;
			break;
		case NV2A_COLOR_FORMAT::X8R8G8B8_Z8R8G8B8:
		case NV2A_COLOR_FORMAT::X8R8G8B8_X8R8G8B8:
			*((uint32_t *)addr) = w;
			break;
		case NV2A_COLOR_FORMAT::A8R8G8B8:
			*((uint32_t *)addr) = w;
			break;
		case NV2A_COLOR_FORMAT::B8:
			*addr = (uint8_t)w;
			break;
		default:
			break;
		}
	}
	if (depth_write_enabled)
		dep = depth;
	if (depthformat_rendertarget == NV2A_RT_DEPTH_FORMAT::Z24S8) {
		deptsten = (dep << 8) | sten;
		*daddr32 = deptsten;
	}
	else if (depthformat_rendertarget == NV2A_RT_DEPTH_FORMAT::Z16) {
		deptsten = dep >> 8;
		*daddr16 = (uint16_t)deptsten;
	}
}

void nv2a_renderer::render_color(int32_t scanline, const extent_t &extent, const nvidia_object_data &objectdata, int threadid)
{
	int x, lx;

	lx = limits_rendertarget.right();
	if ((extent.startx < 0) && (extent.stopx <= 0))
		return;
	if ((extent.startx > lx) && (extent.stopx > lx))
		return;
	x = extent.stopx - extent.startx; // number of pixels to draw (start inclusive, end exclusive)
	if (extent.stopx > lx)
		x = x - (extent.stopx - lx - 1);
	x--;
	while (x >= 0) {
		uint32_t a8r8g8b8;
		int z;
		int ca, cr, cg, cb;
		int xp = extent.startx + x; // x coordinate of current pixel

		cb = ((extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_B].start + (double)x*extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_B].dpdx))*255.0f;
		cg = ((extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_G].start + (double)x*extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_G].dpdx))*255.0f;
		cr = ((extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_R].start + (double)x*extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_R].dpdx))*255.0f;
		ca = ((extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_A].start + (double)x*extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_A].dpdx))*255.0f;
		a8r8g8b8 = (ca << 24) + (cr << 16) + (cg << 8) + cb; // pixel color obtained by interpolating the colors of the vertices
		z = (extent.param[(int)VERTEX_PARAMETER::PARAM_Z].start + (double)x*extent.param[(int)VERTEX_PARAMETER::PARAM_Z].dpdx);
		write_pixel(xp, scanline, a8r8g8b8, z);
		x--;
	}
}

void nv2a_renderer::render_texture_simple(int32_t scanline, const extent_t &extent, const nvidia_object_data &objectdata, int threadid)
{
	int x, lx;
	uint32_t a8r8g8b8;

	if (!objectdata.data->texture[0].enabled) {
		return;
	}
	lx = limits_rendertarget.right();
	if ((extent.startx < 0) && (extent.stopx <= 0))
		return;
	if ((extent.startx > lx) && (extent.stopx > lx))
		return;
	x = extent.stopx - extent.startx; // number of pixels to draw (start inclusive, end exclusive)
	if (extent.stopx > lx)
		x = x - (extent.stopx - lx - 1);
	x--;
	while (x >= 0) {
		int up, vp;
		int z;
		int xp = extent.startx + x; // x coordinate of current pixel

		if (objectdata.data->texture[0].rectangle == false) {
			up = (extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_U].start + (double)x*extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_U].dpdx)*(double)(objectdata.data->texture[0].sizeu - 1); // x coordinate of texel in texture
			vp = (extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_V].start + (double)x*extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_V].dpdx)*(double)(objectdata.data->texture[0].sizev - 1); // y coordinate of texel in texture
		} else
		{
			up = extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_U].start + (double)x*extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_U].dpdx; // x coordinate of texel in texture
			vp = extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_V].start + (double)x*extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_V].dpdx; // y coordinate of texel in texture
		}
		a8r8g8b8 = texture_get_texel(0, up, vp);
		z = (extent.param[(int)VERTEX_PARAMETER::PARAM_Z].start + (double)x*extent.param[(int)VERTEX_PARAMETER::PARAM_Z].dpdx);
		write_pixel(xp, scanline, a8r8g8b8, z);
		x--;
	}
}

void nv2a_renderer::render_register_combiners(int32_t scanline, const extent_t &extent, const nvidia_object_data &objectdata, int threadid)
{
	int x, lx, xp;
	int up, vp;
	int ca, cr, cg, cb;
	uint32_t color[6];
	uint32_t a8r8g8b8;
	int z;
	int n;

	color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0;

	lx = limits_rendertarget.right();
	if ((extent.startx < 0) && (extent.stopx <= 0))
		return;
	if ((extent.startx > lx) && (extent.stopx > lx))
		return;
	x = extent.stopx - extent.startx; // number of pixels to draw (start inclusive, end exclusive)
	if (extent.stopx > lx)
		x = x - (extent.stopx - lx - 1);
	x--;
	std::lock_guard<std::mutex> lock(combiner.lock); // needed since multithreading is not supported yet
	while (x >= 0) {
		xp = extent.startx + x;
		// 1: fetch data
		// 1.1: interpolated color from vertices
		cb = ((extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_B].start + (double)x*extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_B].dpdx))*255.0f;
		cg = ((extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_G].start + (double)x*extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_G].dpdx))*255.0f;
		cr = ((extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_R].start + (double)x*extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_R].dpdx))*255.0f;
		ca = ((extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_A].start + (double)x*extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_A].dpdx))*255.0f;
		color[0] = (ca << 24) + (cr << 16) + (cg << 8) + cb; // pixel color obtained by interpolating the colors of the vertices
		color[1] = 0; // lighting not yet
		// 1.2: color for each of the 4 possible textures
		for (n = 0; n < 4; n++) {
			if (texture[n].enabled) {
				if (texture[n].rectangle == false) {
					up = (extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_U + n * 2].start + (double)x*extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_U + n * 2].dpdx)*(double)(objectdata.data->texture[n].sizeu - 1);
					vp = (extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_V + n * 2].start + (double)x*extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_V + n * 2].dpdx)*(double)(objectdata.data->texture[n].sizev - 1);
				} else
				{
					up = extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_U + n * 2].start + (double)x*extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_U + n * 2].dpdx;
					vp = extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_V + n * 2].start + (double)x*extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_V + n * 2].dpdx;
				}
				color[n + 2] = texture_get_texel(n, up, vp);
			}
		}
		// 2: compute
		// 2.1: initialize
		combiner_initialize_registers(color);
		// 2.2: general cmbiner stages
		for (n = 0; n < combiner.stages; n++) {
			// 2.2.1 initialize
			combiner_initialize_stage(n);
			// 2.2.2 map inputs
			combiner_map_input(n);
			// 2.2.3 compute possible outputs
			combiner_compute_rgb_outputs(n);
			combiner_compute_a_outputs(n);
			// 2.2.4 map outputs to registers
			combiner_map_output(n);
		}
		// 2.3: final cmbiner stage
		combiner_initialize_final();
		combiner_map_final_input();
		combiner_final_output();
		a8r8g8b8 = combiner_float_argb8(combiner.output);
		// 3: write pixel
		z = (extent.param[(int)VERTEX_PARAMETER::PARAM_Z].start + (double)x*extent.param[(int)VERTEX_PARAMETER::PARAM_Z].dpdx);
		write_pixel(xp, scanline, a8r8g8b8, z);
		x--;
	}
}

#if 0
const char *rc_mapping_str[] = {
	"UNSIGNED_IDENTITY",
	"UNSIGNED_INVERT",
	"EXPAND_NORMAL",
	"EXPAND_NEGATE",
	"HALF_BIAS_NORMAL",
	"HALF_BIAS_NEGATE",
	"SIGNED_IDENTITY",
	"SIGNED_NEGATE"
};

const char *rc_usage_rgb_str[] = {
	"RGB",
	"ALPHA"
};

const char *rc_usage_alpha_str[] = {
	"BLUE",
	"ALPHA"
};

const char *rc_variable_str[] = {
	"ZERO",
	"CONSTANT_COLOR0",
	"CONSTANT_COLOR1",
	"FOG",
	"PRIMARY_COLOR",
	"SECONDARY_COLOR",
	"???",
	"???",
	"TEXTURE0",
	"TEXTURE1",
	"TEXTURE2",
	"TEXTURE3",
	"SPARE0",
	"SPARE1",
	"SPARE0_PLUS_SECONDARY_COLOR",
	"E_TIMES_F"
};

const char *rc_bias_str[] = {
	"NONE",
	"BIAS_BY_NEGATIVE_ONE_HALF"
};

const char *rc_scale_str[] = {
	"NONE",
	"SCALE_BY_TWO",
	"SCALE_BY_FOUR",
	"SCALE_BY_ONE_HALF"
};

/* Dump the current setup of the register combiners */
void dumpcombiners(uint32_t *m)
{
	int a, b, n, v;

	n = m[0x1e60 / 4] & 0xf;
	printf("Combiners active: %d\n\r", n);
	for (a = 0; a < n; a++) {
		printf("Combiner %d\n\r", a + 1);
		printf(" RC_IN_ALPHA %08X\n\r", m[0x0260 / 4 + a]);
		for (b = 24; b >= 0; b = b - 8) {
			v = (m[0x0260 / 4 + a] >> b) & 0xf;
			printf("  %c_INPUT %s\n\r", 'A' + 3 - b / 8, rc_variable_str[v]);
			v = (m[0x0260 / 4 + a] >> (b + 4)) & 1;
			printf("  %c_COMPONENT_USAGE %s\n\r", 'A' + 3 - b / 8, rc_usage_alpha_str[v]);
			v = (m[0x0260 / 4 + a] >> (b + 5)) & 7;
			printf("  %c_MAPPING %s\n\r", 'A' + 3 - b / 8, rc_mapping_str[v]);
		}
		printf(" RC_IN_RGB %08X\n\r", m[0x0ac0 / 4 + a]);
		for (b = 24; b >= 0; b = b - 8) {
			v = (m[0x0ac0 / 4 + a] >> b) & 0xf;
			printf("  %c_INPUT %s\n\r", 'A' + 3 - b / 8, rc_variable_str[v]);
			v = (m[0x0ac0 / 4 + a] >> (b + 4)) & 1;
			printf("  %c_COMPONENT_USAGE %s\n\r", 'A' + 3 - b / 8, rc_usage_rgb_str[v]);
			v = (m[0x0ac0 / 4 + a] >> (b + 5)) & 7;
			printf("  %c_MAPPING %s\n\r", 'A' + 3 - b / 8, rc_mapping_str[v]);
		}
		printf(" RC_OUT_ALPHA %08X\n\r", m[0x0aa0 / 4 + a]);
		v = m[0x0aa0 / 4 + a] & 0xf;
		printf("  CD_OUTPUT %s\n\r", rc_variable_str[v]);
		v = (m[0x0aa0 / 4 + a] >> 4) & 0xf;
		printf("  AB_OUTPUT %s\n\r", rc_variable_str[v]);
		v = (m[0x0aa0 / 4 + a] >> 8) & 0xf;
		printf("  SUM_OUTPUT %s\n\r", rc_variable_str[v]);
		v = (m[0x0aa0 / 4 + a] >> 12) & 1;
		printf("  CD_DOT_PRODUCT %d\n\r", v);
		v = (m[0x0aa0 / 4 + a] >> 13) & 1;
		printf("  AB_DOT_PRODUCT %d\n\r", v);
		v = (m[0x0aa0 / 4 + a] >> 14) & 1;
		printf("  MUX_SUM %d\n\r", v);
		v = (m[0x0aa0 / 4 + a] >> 15) & 1;
		printf("  BIAS %s\n\r", rc_bias_str[v]);
		v = (m[0x0aa0 / 4 + a] >> 16) & 3;
		printf("  SCALE %s\n\r", rc_scale_str[v]);
		//v=(m[0x0aa0/4+a] >> 27) & 7;
		printf(" RC_OUT_RGB %08X\n\r", m[0x1e40 / 4 + a]);
		v = m[0x1e40 / 4 + a] & 0xf;
		printf("  CD_OUTPUT %s\n\r", rc_variable_str[v]);
		v = (m[0x1e40 / 4 + a] >> 4) & 0xf;
		printf("  AB_OUTPUT %s\n\r", rc_variable_str[v]);
		v = (m[0x1e40 / 4 + a] >> 8) & 0xf;
		printf("  SUM_OUTPUT %s\n\r", rc_variable_str[v]);
		v = (m[0x1e40 / 4 + a] >> 12) & 1;
		printf("  CD_DOT_PRODUCT %d\n\r", v);
		v = (m[0x1e40 / 4 + a] >> 13) & 1;
		printf("  AB_DOT_PRODUCT %d\n\r", v);
		v = (m[0x1e40 / 4 + a] >> 14) & 1;
		printf("  MUX_SUM %d\n\r", v);
		v = (m[0x1e40 / 4 + a] >> 15) & 1;
		printf("  BIAS %s\n\r", rc_bias_str[v]);
		v = (m[0x1e40 / 4 + a] >> 16) & 3;
		printf("  SCALE %s\n\r", rc_scale_str[v]);
		//v=(m[0x1e40/4+a] >> 27) & 7;
		printf("\n\r");
	}
	printf("Combiner final %08X %08X\n\r", m[0x0288 / 4], m[0x028c / 4]);
	for (a = 24; a >= 0; a = a - 8) {
		n = (m[0x0288 / 4] >> a) & 0xf;
		printf("  %c_INPUT %s\n\r", 'A' + 3 - a / 8, rc_variable_str[n]);
		n = (m[0x0288 / 4] >> (a + 4)) & 1;
		printf("  %c_COMPONENT_USAGE %s\n\r", 'A' + 3 - a / 8, rc_usage_rgb_str[n]);
		n = (m[0x0288 / 4] >> (a + 5)) & 7;
		printf("  %c_MAPPING %s\n\r", 'A' + 3 - a / 8, rc_mapping_str[n]);
	}
	for (a = 24; a >= 8; a = a - 8) {
		n = (m[0x028c / 4] >> a) & 0xf;
		printf("  %c_INPUT %s\n\r", 'E' + 3 - a / 8, rc_variable_str[n]);
		n = (m[0x028c / 4] >> (a + 4)) & 1;
		printf("  %c_COMPONENT_USAGE %s\n\r", 'E' + 3 - a / 8, rc_usage_rgb_str[n]);
		n = (m[0x028c / 4] >> (a + 5)) & 7;
		printf("  %c_MAPPING %s\n\r", 'E' + 3 - a / 8, rc_mapping_str[n]);
	}
	n = (m[0x028c / 4] >> 7) & 1;
	printf(" color sum clamp: %d\n\r", n);
}
#endif

void nv2a_renderer::extract_packed_float(uint32_t data, float &first, float &second, float &third)
{
	int32_t p1, p2, p3;
	int32_t e1, e2, e3;
	int32_t m1, m2, m3;
	float scale, decimal;
	union
	{
		float f;
		uint32_t i;
	} i2f;

	// convert r11g11b10f to 3 float values
	// each 32 bit words contains 2 11 bit float values and one 10 bit float value
	p1 = data & 0b11111111111;
	p2 = (data >> 11) & 0b11111111111;
	p3 = (data >> 22) & 0b1111111111;
	// 11 bit values have 6 bits of mantissa and 5 of exponent, 10 bit values have 5 bits of mantissa and 5 of exponent
	m1 = p1 & 0b111111;
	e1 = (p1 >> 6) & 0b11111;
	m2 = p2 & 0b111111;
	e2 = (p2 >> 6) & 0b11111;
	m3 = p3 & 0b11111;
	e3 = (p3 >> 5) & 0b11111;
	// the following is based on routine UF11toF32 in appendix G of the "OpenGL Programming Guide 8th edition" book
	if (e1 == 0) {
		if (m1 != 0) {
			scale = 1.0 / (1 << 20);
			first = scale * m1;
		}
		else
			first = 0;
	}
	else if (e1 == 31) {
		i2f.i = 0x7f800000 | m1;
		first = i2f.f;
	}
	else {
		e1 -= 15;
		if (e1 < 0) {
			scale = 1.0 / (1 << -e1);
		}
		else {
			scale = 1 << e1;
		}
		decimal = 1.0 + (float)m1 / 64;
		first = scale * decimal;
	}
	if (e2 == 0) {
		if (m2 != 0) {
			scale = 1.0 / (1 << 20);
			second = scale * m2;
		}
		else
			second = 0;
	}
	else if (e2 == 31) {
		i2f.i = 0x7f800000 | m2;
		second = i2f.f;
	}
	else {
		e2 -= 15;
		if (e2 < 0) {
			scale = 1.0 / (1 << -e2);
		}
		else {
			scale = 1 << e2;
		}
		decimal = 1.0 + (float)m2 / 64;
		second = scale * decimal;
	}
	if (e3 == 0) {
		if (m3 != 0) {
			scale = 1.0 / (1 << 20);
			third = scale * m3;
		}
		else
			third = 0;
	}
	else if (e3 == 31) {
		i2f.i = 0x7f800000 | m3;
		third = i2f.f;
	}
	else {
		e3 -= 15;
		if (e3 < 0) {
			scale = 1.0 / (1 << -e3);
		}
		else {
			scale = 1 << e3;
		}
		decimal = 1.0 + (float)m3 / 32;
		third = scale * decimal;
	}
}


void nv2a_renderer::read_vertex(address_space & space, offs_t address, vertex_nv &vertex, int attrib)
{
	uint32_t u;
	int c, d, l;

	l = vertexbuffer_size[attrib];
	switch (vertexbuffer_kind[attrib]) {
	case NV2A_VTXBUF_TYPE::FLOAT:
		vertex.attribute[attrib].fv[0] = 0;
		vertex.attribute[attrib].fv[1] = 0;
		vertex.attribute[attrib].fv[2] = 0;
		vertex.attribute[attrib].fv[3] = 1.0;
		for (c = d = 0; c < l; c++) {
			vertex.attribute[attrib].iv[c] = space.read_dword(address + d);
			d = d + 4;
		}
		break;
	case NV2A_VTXBUF_TYPE::UBYTE_OGL:
		u = space.read_dword(address + 0);
		for (c = l-1; c >= 0; c--) {
			vertex.attribute[attrib].fv[c] = (u & 0xff) / 255.0;
			u = u >> 8;
		}
		break;
	case  NV2A_VTXBUF_TYPE::UBYTE_D3D:
		u = space.read_dword(address + 0);
		for (c = 0; c < l; c++) {
			vertex.attribute[attrib].fv[c] = (u & 0xff) / 255.0;
			u = u >> 8;
		}
		break;
	case NV2A_VTXBUF_TYPE::FLOAT_PACKED: // 3 floating point numbers packed into 32 bits
		u = space.read_dword(address + 0);
		extract_packed_float(u, vertex.attribute[attrib].fv[0], vertex.attribute[attrib].fv[1], vertex.attribute[attrib].fv[2]);
		vertex.attribute[attrib].fv[3] = 1.0;
		break;
	default:
		vertex.attribute[attrib].fv[0] = 0;
		vertex.attribute[attrib].fv[1] = 0;
		vertex.attribute[attrib].fv[2] = 0;
		vertex.attribute[attrib].fv[3] = 1.0;
		machine().logerror("Unsupported vertex type in read_vertex !\n");
	}
}

/* Read vertices data from system memory. Method 0x1800 and 0x1808 */
int nv2a_renderer::read_vertices_0x180x(address_space & space, vertex_nv *destination, uint32_t address, int limit)
{
	uint32_t m;
	int a, b;

#ifdef MAME_DEBUG
	memset(destination, 0, sizeof(vertex_nv)*limit);
#endif
	for (m = 0; m < limit; m++) {
		memcpy(&destination[m], &persistvertexattr, sizeof(persistvertexattr));
		b = enabled_vertex_attributes;
		for (a = 0; a < 16; a++) {
			if (b & 1) {
				read_vertex(space, vertexbuffer_address[a] + vertex_indexes[indexesleft_first] * vertexbuffer_stride[a], destination[m], a);
			}
			b = b >> 1;
		}
		indexesleft_first = (indexesleft_first + 1) & 1023;
		indexesleft_count--;
	}
	return limit;
}

/* Read vertices data from system memory. Method 0x1810 */
int nv2a_renderer::read_vertices_0x1810(address_space & space, vertex_nv *destination, int offset, int limit)
{
	uint32_t m;
	int a, b;

#ifdef MAME_DEBUG
	memset(destination, 0, sizeof(vertex_nv)*limit);
#endif
	for (m = 0; m < limit; m++) {
		memcpy(&destination[m], &persistvertexattr, sizeof(persistvertexattr));
		b = enabled_vertex_attributes;
		for (a = 0; a < 16; a++) {
			if (b & 1) {
				read_vertex(space, vertexbuffer_address[a] + (m + offset)*vertexbuffer_stride[a], destination[m], a);
			}
			b = b >> 1;
		}
	}
	return m;
}

/* Read vertices data from system memory. Method 0x1818 */
int nv2a_renderer::read_vertices_0x1818(address_space & space, vertex_nv *destination, uint32_t address, int limit)
{
	uint32_t m, vwords;
	int a, b;

#ifdef MAME_DEBUG
	memset(destination, 0, sizeof(vertex_nv)*limit);
#endif
	vwords = vertex_attribute_words[15] + vertex_attribute_offset[15];
	for (m = 0; m < limit; m++) {
		memcpy(&destination[m], &persistvertexattr, sizeof(persistvertexattr));
		b = enabled_vertex_attributes;
		for (a = 0; a < 16; a++) {
			if (b & 1) {
				read_vertex(space, address + vertex_attribute_offset[a] * 4, destination[m], a);
			}
			b = b >> 1;
		}
		address = address + vwords * 4;
	}
	return (int)(m*vwords);
}

void nv2a_renderer::compute_supersample_factors(float &horizontal, float &vertical)
{
	float mx, my;

	mx = 1;
	my = 1;
	switch (((antialias_control & 1) << 2) | antialiasing_rendertarget)
	{
	case 0:
		mx = my = 1;
		break;
	case 1:
		mx = 2; my = 1;
		break;
	case 2:
		mx = my = 2;
		break;
	case 4:
		mx = my = 1;
		break;
	case 5:
		mx = 2;
		my = 1;
		break;
	case 6:
		mx = 2;
		my = 2;
		break;
	default:
		mx = my = 1;
	}
	horizontal = mx;
	vertical = my;
}

void nv2a_renderer::convert_vertices_poly(vertex_nv *source, nv2avertex_t *destination, int count)
{
	vertex_nv vert[4];
	int m, u;
	float v[4];

	// take each vertex with its attributes and obtain data for drawing
	// should use either the vertex program or transformation matrices
	if (vertex_pipeline == 4) {
		// transformation matrices
		// this part needs more testing
		for (m = 0; m < count; m++) {
			for (int i = 0; i < 4; i++) {
				v[i] = 0;
				for (int j = 0; j < 4; j++)
					v[i] += matrix.composite[i][j] * source[m].attribute[0].fv[j];
			};
			destination[m].w = v[3];
			destination[m].x = (v[0] / v[3])*supersample_factor_x; // source[m].attribute[0].fv[0];
			destination[m].y = (v[1] / v[3])*supersample_factor_y; // source[m].attribute[0].fv[1];
			destination[m].p[(int)VERTEX_PARAMETER::PARAM_Z] = v[2] / v[3];
			for (u = (int)VERTEX_PARAMETER::PARAM_COLOR_B; u <= (int)VERTEX_PARAMETER::PARAM_COLOR_A; u++) // 0=b 1=g 2=r 3=a
				destination[m].p[u] = source[m].attribute[3].fv[u];
			for (u = 0; u < 4; u++) {
				destination[m].p[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_U + u * 2] = source[m].attribute[9 + u].fv[0];
				destination[m].p[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_V + u * 2] = source[m].attribute[9 + u].fv[1];
			}
		}
	}
	else {
		// vertex program
		// run vertex program
		vertexprogram.exec.process(vertexprogram.start_instruction, source, vert, count);
		// the output of the vertex program has the perspective divide, viewport scale and offset already applied
		// copy data for poly.c
		for (m = 0; m < count; m++) {
			destination[m].w = vert[m].attribute[0].fv[3];
			destination[m].x = (vert[m].attribute[0].fv[0] - 0.53125) * supersample_factor_x;
			destination[m].y = (vert[m].attribute[0].fv[1] - 0.53125) * supersample_factor_y;
			for (u = (int)VERTEX_PARAMETER::PARAM_COLOR_B; u <= (int)VERTEX_PARAMETER::PARAM_COLOR_A; u++) // 0=b 1=g 2=r 3=a
				destination[m].p[u] = vert[m].attribute[3].fv[u];
			for (u = 0; u < 4; u++) {
				destination[m].p[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_U + u * 2] = vert[m].attribute[9 + u].fv[0];
				destination[m].p[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_V + u * 2] = vert[m].attribute[9 + u].fv[1];
			}
			destination[m].p[(int)VERTEX_PARAMETER::PARAM_Z] = vert[m].attribute[0].fv[2];
		}
	}
}

void nv2a_renderer::clear_render_target(int what, uint32_t value)
{
	int xi, yi, xf, yf;
	int x, y;
	uint32_t color;
	uint8_t *addr;
	uint32_t mask;
	uint32_t offset;

	if (what == 0)
		return;
	mask = 0;
	switch (colorformat_rendertarget) {
	case NV2A_COLOR_FORMAT::R5G6B5:
		if (what & 1)
			mask = 0x1f;
		if (what & 2)
			mask = mask | 0x07e0;
		if (what & 4)
			mask = mask | 0xf800;
		break;
	case NV2A_COLOR_FORMAT::X8R8G8B8_Z8R8G8B8:
	case NV2A_COLOR_FORMAT::X8R8G8B8_X8R8G8B8:
		for (x = 3; x >= 0; x--) {
			if (what & 8)
				mask = (mask << 8) | 255;
			what = what << 1;
		}
		break;
	case NV2A_COLOR_FORMAT::A8R8G8B8:
		for (x = 3; x >= 0; x--) {
			if (what & 8)
				mask = (mask << 8) | 255;
			what = what << 1;
		}
		break;
	case NV2A_COLOR_FORMAT::B8:
		if (what & 1)
			mask = 255;
		break;
	default:
		return;
	}
	xi = clear_rendertarget.left()*supersample_factor_x;
	yi = clear_rendertarget.top()*supersample_factor_y;
	xf = clear_rendertarget.right()*supersample_factor_x;
	yf = clear_rendertarget.bottom()*supersample_factor_y;
	if ((xi < limits_rendertarget.left()) && (xf < limits_rendertarget.left()))
		return;
	if ((xi > limits_rendertarget.right()) && (xf > limits_rendertarget.right()))
		return;
	if ((yi < limits_rendertarget.top()) && (yf < limits_rendertarget.top()))
		return;
	if ((yi > limits_rendertarget.bottom()) && (yf > limits_rendertarget.bottom()))
		return;
	if (xi < limits_rendertarget.left())
		xi = limits_rendertarget.left();
	if (xf > limits_rendertarget.right())
		xf = limits_rendertarget.right();
	if (yi < limits_rendertarget.top())
		yi = limits_rendertarget.top();
	if (yf > limits_rendertarget.bottom())
		yf = limits_rendertarget.bottom();
	if (type_rendertarget == NV2A_RT_TYPE::SWIZZLED)
		offset = (dilated0[dilate_rendertarget][xf] + dilated1[dilate_rendertarget][yf]) * bytespixel_rendertarget;
	else // type_rendertarget == LINEAR
		offset = pitch_rendertarget * yf + xf * bytespixel_rendertarget;
	addr = (uint8_t *)rendertarget + offset;
	if ((addr < basemempointer) || (addr > topmempointer))
	{
		machine().logerror("Bad memory pointer computed in clear_render_target !\n");
		return;
	}

	for (y = yi; y <= yf; y++)
		for (x = xi; x <= xf; x++) {
			if (type_rendertarget == NV2A_RT_TYPE::SWIZZLED)
				offset = (dilated0[dilate_rendertarget][x] + dilated1[dilate_rendertarget][y]) * bytespixel_rendertarget;
			else // type_rendertarget == LINEAR
				offset = pitch_rendertarget * y + x * bytespixel_rendertarget;
			switch (colorformat_rendertarget) {
			case NV2A_COLOR_FORMAT::R5G6B5:
				addr = (uint8_t *)rendertarget + offset;
				color = *((uint16_t *)addr);
				break;
			case NV2A_COLOR_FORMAT::X8R8G8B8_Z8R8G8B8:
			case NV2A_COLOR_FORMAT::X8R8G8B8_X8R8G8B8:
				addr = (uint8_t *)rendertarget + offset;
				color = *((uint32_t *)addr);
				break;
			case NV2A_COLOR_FORMAT::A8R8G8B8:
				addr = (uint8_t *)rendertarget + offset;
				color = *((uint32_t *)addr);
				break;
			case NV2A_COLOR_FORMAT::B8:
				addr = (uint8_t *)rendertarget + offset;
				color = *addr;
				break;
			default:
				return;
			}
			color = (color & ~mask) | (value & mask);
			switch (colorformat_rendertarget) {
			case NV2A_COLOR_FORMAT::R5G6B5:
				*((uint16_t *)addr) = color;
				break;
			case NV2A_COLOR_FORMAT::X8R8G8B8_Z8R8G8B8:
			case NV2A_COLOR_FORMAT::X8R8G8B8_X8R8G8B8:
				*((uint32_t *)addr) = color;
				break;
			case NV2A_COLOR_FORMAT::A8R8G8B8:
				*((uint32_t *)addr) = color;
				break;
			case NV2A_COLOR_FORMAT::B8:
				*addr = color;
				break;
			default:
				return;
			}
		}
#ifdef LOG_NV2A
	printf("clearscreen\n\r");
#endif
}

void nv2a_renderer::clear_depth_buffer(int what, uint32_t value)
{
	int xi, yi, xf, yf;
	int x, y;
	uint32_t color;
	uint8_t *addr;
	uint32_t mask;
	uint32_t offset;
	uint32_t bpp;

	if (what == 0)
		return;
	mask = 0;
	switch (depthformat_rendertarget) {
	case NV2A_RT_DEPTH_FORMAT::Z24S8:
		if (what & 1)
			mask = 0xffffff00;
		if (what & 2)
			mask = mask | 0xff;
		bpp = 4;
		break;
	case NV2A_RT_DEPTH_FORMAT::Z16:
		if (what & 1)
			mask = 0xffff;
		bpp = 2;
		break;
	default:
		return;
	}
	xi = clear_rendertarget.left()*supersample_factor_x;
	yi = clear_rendertarget.top()*supersample_factor_y;
	xf = clear_rendertarget.right()*supersample_factor_x;
	yf = clear_rendertarget.bottom()*supersample_factor_y;
	if ((xi < limits_rendertarget.left()) && (xf < limits_rendertarget.left()))
		return;
	if ((xi > limits_rendertarget.right()) && (xf > limits_rendertarget.right()))
		return;
	if ((yi < limits_rendertarget.top()) && (yf < limits_rendertarget.top()))
		return;
	if ((yi > limits_rendertarget.bottom()) && (yf > limits_rendertarget.bottom()))
		return;
	if (xi < limits_rendertarget.left())
		xi = limits_rendertarget.left();
	if (xf > limits_rendertarget.right())
		xf = limits_rendertarget.right();
	if (yi < limits_rendertarget.top())
		yi = limits_rendertarget.top();
	if (yf > limits_rendertarget.bottom())
		yf = limits_rendertarget.bottom();
	offset = pitch_depthbuffer * yf + xf * bpp;
	addr = (uint8_t *)depthbuffer + offset;
	if ((addr < basemempointer) || (addr > topmempointer))
	{
		machine().logerror("Bad memory pointer computed in clear_depth_buffer !\n");
		return;
	}

	for (y = yi; y <= yf; y++)
		for (x = xi; x <= xf; x++) {
			offset = pitch_depthbuffer * y + x * bpp;
			switch (depthformat_rendertarget) {
			case NV2A_RT_DEPTH_FORMAT::Z16:
				addr = (uint8_t *)depthbuffer + offset;
				color = *((uint16_t *)addr);
				break;
			case NV2A_RT_DEPTH_FORMAT::Z24S8:
				addr = (uint8_t *)depthbuffer + offset;
				color = *((uint32_t *)addr);
				break;
			default:
				return;
			}
			color = (color & ~mask) | (value & mask);
			switch (depthformat_rendertarget) {
			case NV2A_RT_DEPTH_FORMAT::Z16:
				addr = (uint8_t *)depthbuffer + offset;
				*((uint16_t *)addr) = color;
				break;
			case NV2A_RT_DEPTH_FORMAT::Z24S8:
				addr = (uint8_t *)depthbuffer + offset;
				*((uint32_t *)addr) = color;
				break;
			default:
				return;
			}
		}
}

uint32_t nv2a_renderer::render_triangle_culling(const rectangle &cliprect, render_delegate callback, int paramcount, nv2avertex_t &_v1, nv2avertex_t &_v2, nv2avertex_t &_v3)
{
	float areax2;
	NV2A_GL_CULL_FACE face = NV2A_GL_CULL_FACE::FRONT;

	if (backface_culling_enabled == false)
		return render_triangle(cliprect, callback, paramcount, _v1, _v2, _v3);
	if (backface_culling_culled == NV2A_GL_CULL_FACE::FRONT_AND_BACK)
	{
		triangles_bfculled++;
		return 0;
	}
	areax2 = _v1.x*(_v2.y - _v3.y) + _v2.x*(_v3.y - _v1.y) + _v3.x*(_v1.y - _v2.y);
	if (backface_culling_winding == NV2A_GL_FRONT_FACE::CCW)
	{
		if (-areax2 <= 0)
			face = NV2A_GL_CULL_FACE::BACK;
		else
			face = NV2A_GL_CULL_FACE::FRONT;
	} else
	{
		if (areax2 <= 0)
			face = NV2A_GL_CULL_FACE::BACK;
		else
			face = NV2A_GL_CULL_FACE::FRONT;
	}
	if (face == NV2A_GL_CULL_FACE::FRONT)
		if (backface_culling_culled == NV2A_GL_CULL_FACE::BACK)
			return render_triangle(cliprect, callback, paramcount, _v1, _v2, _v3);
	if (face == NV2A_GL_CULL_FACE::BACK)
		if (backface_culling_culled == NV2A_GL_CULL_FACE::FRONT)
			return render_triangle(cliprect, callback, paramcount, _v1, _v2, _v3);
	triangles_bfculled++;
	return 0;
}

int nv2a_renderer::clip_triangle_w(nv2avertex_t *vi[3], nv2avertex_t *vo)
{
	int idx_prev, idx_curr;
	int neg_prev, neg_curr;
	double tfactor;
	int idx;
	const double wthreshold = 0.000001;

	idx_prev = 2;
	idx_curr = 0;
	idx = 0;
	neg_prev = vi[idx_prev]->w < wthreshold ? 1 : 0;
	while (idx_curr < 3)
	{
		neg_curr = vi[idx_curr]->w < wthreshold ? 1 : 0;
		if (neg_curr ^ neg_prev)
		{
			tfactor = (wthreshold - vi[idx_prev]->w) / (vi[idx_curr]->w - vi[idx_prev]->w);
			// compute values for the new intermediate point
			vo[idx].x = ((vi[idx_curr]->x - vi[idx_prev]->x) * tfactor) + vi[idx_prev]->x;
			vo[idx].y = ((vi[idx_curr]->y - vi[idx_prev]->y) * tfactor) + vi[idx_prev]->y;
			vo[idx].w = ((vi[idx_curr]->w - vi[idx_prev]->w) * tfactor) + vi[idx_prev]->w;
			for (int n = 0; n < 13; n++)
				vo[idx].p[n] = ((vi[idx_curr]->p[n] - vi[idx_prev]->p[n]) * tfactor) + vi[idx_prev]->p[n];
			idx++;
		}
		if (neg_curr == 0)
		{
			vo[idx].x = vi[idx_curr]->x;
			vo[idx].y = vi[idx_curr]->y;
			vo[idx].w = vi[idx_curr]->w;
			for (int n = 0; n < 13; n++)
				vo[idx].p[n] = vi[idx_curr]->p[n];
			idx++;
		}
		neg_prev = neg_curr;
		idx_prev = idx_curr;
		idx_curr++;
	}
	return idx;
}

uint32_t nv2a_renderer::render_triangle_clipping(const rectangle &cliprect, render_delegate callback, int paramcount, nv2avertex_t &_v1, nv2avertex_t &_v2, nv2avertex_t &_v3)
{
	nv2avertex_t *vi[3];
	nv2avertex_t vo[8];
	int nv;

	if ((_v1.w > 0) && (_v2.w > 0) && (_v3.w > 0))
		return render_triangle_culling(cliprect, callback, paramcount, _v1, _v2, _v3);
	if (enable_clipping_w == false)
		return 0;
	if ((_v1.w <= 0) && (_v2.w <= 0) && (_v3.w <= 0))
		return 0;
	// assign the elements of the array
	vi[0] = &_v1;
	vi[1] = &_v2;
	vi[2] = &_v3;
	// go back to the state before perpective divide
	if (vertex_pipeline == 4)
	{
		for (int n = 0; n < 3; n++)
		{
			vi[n]->x = (vi[n]->x / (double)supersample_factor_x)*vi[n]->w;
			vi[n]->y = (vi[n]->y / (double)supersample_factor_y)*vi[n]->w;
			vi[n]->p[(int)VERTEX_PARAMETER::PARAM_Z] = vi[n]->p[(int)VERTEX_PARAMETER::PARAM_Z] * vi[n]->w;
		}
	} else
	{
		for (int n = 0; n < 3; n++)
		{
			// remove translate
			vi[n]->x = vi[n]->x - matrix.translate[0];
			vi[n]->y = vi[n]->y - matrix.translate[1];
			vi[n]->p[(int)VERTEX_PARAMETER::PARAM_Z] = vi[n]->p[(int)VERTEX_PARAMETER::PARAM_Z] - matrix.translate[2];
			// remove perspective divide
			vi[n]->x = vi[n]->x * vi[n]->w;
			vi[n]->y = vi[n]->y * vi[n]->w;
			vi[n]->p[(int)VERTEX_PARAMETER::PARAM_Z] = vi[n]->p[(int)VERTEX_PARAMETER::PARAM_Z] * vi[n]->w;
		}
	}
	// do the clipping
	nv = clip_triangle_w(vi, vo);
	// screen coordinates for the new points
	if (vertex_pipeline == 4)
	{
		for (int n = 0; n < nv; n++)
		{
			vo[n].x = vo[n].x*(double)supersample_factor_x / vo[n].w;
			vo[n].y = vo[n].y*(double)supersample_factor_y / vo[n].w;
			vo[n].p[(int)VERTEX_PARAMETER::PARAM_Z] = vo[n].p[(int)VERTEX_PARAMETER::PARAM_Z] / vo[n].w;
		}
	} else
	{
		for (int n = 0; n < nv; n++)
		{
			// apply perspective divide
			vo[n].x = vo[n].x / vo[n].w;
			vo[n].y = vo[n].y / vo[n].w;
			vo[n].p[(int)VERTEX_PARAMETER::PARAM_Z] = vo[n].p[(int)VERTEX_PARAMETER::PARAM_Z] / vo[n].w;
			// apply translate
			vo[n].x = vo[n].x + matrix.translate[0];
			vo[n].y = vo[n].y + matrix.translate[1];
			vo[n].p[(int)VERTEX_PARAMETER::PARAM_Z] = vo[n].p[(int)VERTEX_PARAMETER::PARAM_Z] + matrix.translate[2];
		}
	}
	for (int n = 1; n <= (nv - 2); n++)
		render_triangle_culling(cliprect, callback, paramcount, vo[0], vo[n], vo[n + 1]);
	return 0;
}

void nv2a_renderer::assemble_primitive(vertex_nv *source, int count, render_delegate &renderspans)
{
	uint32_t pc = primitives_count;

	for (; count > 0; count--) {
		if (primitive_type == NV2A_BEGIN_END::QUADS) {
			convert_vertices_poly(source, vertex_xy + vertex_count + vertex_accumulated, 1);
			vertex_accumulated++;
			if (vertex_accumulated == 4) {
				primitives_count++;
				vertex_accumulated = 0;
				render_triangle_clipping(limits_rendertarget, renderspans, 5 + 4 * 2, vertex_xy[vertex_count], vertex_xy[vertex_count + 1], vertex_xy[vertex_count + 2]);
				render_triangle_clipping(limits_rendertarget, renderspans, 5 + 4 * 2, vertex_xy[vertex_count], vertex_xy[vertex_count + 2], vertex_xy[vertex_count + 3]);
				vertex_count = (vertex_count + 4) & 1023;
				wait();
			}
		}
		else if (primitive_type == NV2A_BEGIN_END::TRIANGLES) {
			convert_vertices_poly(source, vertex_xy + vertex_count + vertex_accumulated, 1);
			vertex_accumulated++;
			if (vertex_accumulated == 3) {
				primitives_count++;
				vertex_accumulated = 0;
				render_triangle_clipping(limits_rendertarget, renderspans, 5 + 4 * 2, vertex_xy[vertex_count], vertex_xy[(vertex_count + 1) & 1023], vertex_xy[(vertex_count + 2) & 1023]); // 4 rgba, 4 texture units 2 uv
				vertex_count = (vertex_count + 3) & 1023;
				wait();
			}
		}
		else if (primitive_type == NV2A_BEGIN_END::TRIANGLE_FAN) {
			if (vertex_accumulated == 0)
			{
				convert_vertices_poly(source, vertex_xy + 1024, 1);
				vertex_accumulated = 1;
			}
			else if (vertex_accumulated == 1)
			{
				convert_vertices_poly(source, vertex_xy, 1);
				vertex_accumulated = 2;
				vertex_count = 1;
			}
			else
			{
				primitives_count++;
				// if software sends the vertices 0 1 2 3 4 5 6
				// hardware will draw triangles made by (0,1,2) (0,2,3) (0,3,4) (0,4,5) (0,5,6)
				convert_vertices_poly(source, vertex_xy + vertex_count, 1);
				render_triangle_clipping(limits_rendertarget, renderspans, 5 + 4 * 2, vertex_xy[1024], vertex_xy[(vertex_count - 1) & 1023], vertex_xy[vertex_count]);
				vertex_count = (vertex_count + 1) & 1023;
				wait();
			}
		}
		else if (primitive_type == NV2A_BEGIN_END::TRIANGLE_STRIP) {
			if (vertex_accumulated == 0)
			{
				convert_vertices_poly(source, vertex_xy, 1);
				vertex_accumulated = 1;
			}
			else if (vertex_accumulated == 1)
			{
				convert_vertices_poly(source, vertex_xy + 1, 1);
				vertex_accumulated = 2;
				vertex_count = 2;
			}
			else
			{
				primitives_count++;
				// if software sends the vertices 0 1 2 3 4 5 6
				// hardware will draw triangles made by (0,1,2) (1,3,2) (2,3,4) (3,5,4) (4,5,6)
				convert_vertices_poly(source, vertex_xy + vertex_count, 1);
				if ((vertex_count & 1) == 0)
					render_triangle_clipping(limits_rendertarget, renderspans, 5 + 4 * 2, vertex_xy[(vertex_count - 2) & 1023], vertex_xy[(vertex_count - 1) & 1023], vertex_xy[vertex_count]);
				else
					render_triangle_clipping(limits_rendertarget, renderspans, 5 + 4 * 2, vertex_xy[(vertex_count - 2) & 1023], vertex_xy[vertex_count], vertex_xy[(vertex_count - 1) & 1023]);
				vertex_count = (vertex_count + 1) & 1023;
				wait();
			}
		}
		else if (primitive_type == NV2A_BEGIN_END::QUAD_STRIP) {
			if (vertex_accumulated == 0)
			{
				convert_vertices_poly(source, vertex_xy, 1);
				vertex_accumulated = 1;
			}
			else if (vertex_accumulated == 1)
			{
				convert_vertices_poly(source, vertex_xy + 1, 1);
				vertex_accumulated = 2;
				vertex_count = 0;
			}
			else
			{
				convert_vertices_poly(source, vertex_xy + ((vertex_count + vertex_accumulated) & 1023), 1);
				vertex_accumulated++;
				if (vertex_accumulated == 4)
				{
					primitives_count++;
					// quad is made of vertices vertex count +0 +1 +3 +2
					render_triangle_clipping(limits_rendertarget, renderspans, 5 + 4 * 2, vertex_xy[vertex_count + 0], vertex_xy[vertex_count + 1], vertex_xy[(vertex_count + 3) & 1023]);
					render_triangle_clipping(limits_rendertarget, renderspans, 5 + 4 * 2, vertex_xy[(vertex_count + 3) & 1023], vertex_xy[(vertex_count + 2) & 1023], vertex_xy[vertex_count + 0]);
					vertex_accumulated = 2;
					vertex_count = (vertex_count + 2) & 1023;
					wait();
				}
			}
		}
		else {
			if (vertex_count == 0)
				machine().logerror("Unsupported primitive %d\n", int(primitive_type));
			vertex_count++;
		}
		source++;
	}
	primitives_total_count += primitives_count - pc;
}

void nv2a_renderer::compute_limits_rendertarget(uint32_t chanel, uint32_t subchannel)
{
	uint32_t data;
	int x, w;
	int y, h;

	data = channel[chanel][subchannel].object.method[0x0200 / 4];
	x = data & 0xffff;
	w = (data >> 16) & 0xffff;
	x = x*supersample_factor_x;
	w = w*supersample_factor_x;
	limits_rendertarget.setx(x, x + w - 1);
	data = channel[chanel][subchannel].object.method[0x0204 / 4];
	y = data & 0xffff;
	h = (data >> 16) & 0xffff;
	y = y*supersample_factor_y;
	h = h*supersample_factor_y;
	limits_rendertarget.sety(y, y + h - 1);
}

void nv2a_renderer::compute_size_rendertarget(uint32_t chanel, uint32_t subchannel)
{
	size_rendertarget = pitch_rendertarget*(limits_rendertarget.bottom() + 1);
	size_depthbuffer = pitch_depthbuffer*(limits_rendertarget.bottom() + 1);
}

int nv2a_renderer::geforce_exec_method(address_space & space, uint32_t chanel, uint32_t subchannel, uint32_t method, uint32_t address, int &countlen)
{
	uint32_t maddress;
	uint32_t data;

	maddress = method * 4;
	data = space.read_dword(address);
	channel[chanel][subchannel].object.method[method] = data;
#ifdef LOG_NV2A
	//printf("A:%08X MTHD:%08X D:%08X\n\r",address,maddress,data);
#endif
	if (maddress == 0x17fc) {
#if 0 // useful while debugging to see what coordinates have been used
		static int debugvc = 0;
		if (debugvc)
			if (data == 0)
			{
				printf("%d %d\n\r", (int)primitive_type, vertex_first);
				for (int n = 0; n < vertex_first; n++)
				{
					if (indexesleft_count > 0)
						printf("%d i:%d ", n, vertex_indexes[n]);
					else
						printf("%d ", n);
					printf("X:%f Y:%f Z:%f W:%f x:%f y:%f\n\r", vertex_software[n].attribute[0].fv[0], vertex_software[n].attribute[0].fv[1], vertex_software[n].attribute[0].fv[2], vertex_software[n].attribute[0].fv[3], vertex_xy[n].x, vertex_xy[n].y);
				}
			}
#endif
		vertex_count = 0;
		vertex_first = 0;
		vertex_accumulated = 0;
		indexesleft_count = 0;
		indexesleft_first = 0;
		primitives_count = 0;
		primitive_type = (NV2A_BEGIN_END)data;
		if (data != 0) {
			if (((channel[chanel][subchannel].object.method[0x1e60 / 4] & 7) > 0) && (combiner.used != 0))
				render_spans_callback = render_delegate(&nv2a_renderer::render_register_combiners, this);
			else if (texture[0].enabled)
				render_spans_callback = render_delegate(&nv2a_renderer::render_texture_simple, this);
			else
				render_spans_callback = render_delegate(&nv2a_renderer::render_color, this);
		}
		countlen--;
	}
	if (maddress == 0x1810) {
		// draw vertices
		int offset, count;
		uint32_t n;

		offset = data & 0xffffff;
		count = (data >> 24) & 0xff;
#ifdef LOG_NV2A
		printf("vertex %d %d\n\r", offset, count);
#endif
		for (n = 0; n <= count; n++) {
			read_vertices_0x1810(space, vertex_software + vertex_first, n + offset, 1);
			assemble_primitive(vertex_software + vertex_first, 1, render_spans_callback);
			vertex_first = (vertex_first + 1) & 1023;
		}
		countlen--;
	}
	if ((maddress == 0x1800) || (maddress == 0x1808)) {
		int mult;

		if (maddress == 0x1800)
			mult = 2;
		else
			mult = 1;
		// vertices are selected from the vertex buffer using an array of indexes
		// each dword after 1800 contains two 16 bit index values to select the vartices
		// each dword after 1808 contains a 32 bit index value to select the vartices
		while (countlen > 0) {
			int n;

			data = space.read_dword(address);
			n = indexesleft_first + indexesleft_count;
			if (mult == 2) {
				vertex_indexes[n & 1023] = data & 0xffff;
				vertex_indexes[(n + 1) & 1023] = (data >> 16) & 0xffff;
				indexesleft_count = indexesleft_count + 2;
			}
			else {
				vertex_indexes[n & 1023] = data;
				indexesleft_count = indexesleft_count + 1;
			}
			address += 4;
			countlen--;
			read_vertices_0x180x(space, vertex_software + vertex_first, address, mult);
			assemble_primitive(vertex_software + vertex_first, mult, render_spans_callback);
			vertex_first = (vertex_first + mult) & 1023;
		}
	}
	if (maddress == 0x1818) {
		// vertices are taken from the next words, not from a vertex buffer
		// first send primitive type with 17fc
		// then countlen number of dwords with 1818
		// end with 17fc primitive type 0
		// at 1760 16 words specify the vertex format:for each possible vertex attribute the number of components (0=not present) and type of each
		while (countlen > 0) {
			int c;

			c = read_vertices_0x1818(space, vertex_software + vertex_first, address, 1);
			countlen = countlen - c;
			if (countlen < 0) {
				machine().logerror("Method 0x1818 missing %d words\n", -countlen);
				countlen = 0;
				break;
			}
			address = address + c * 4;
			assemble_primitive(vertex_software + vertex_first, 1, render_spans_callback);
			vertex_first = (vertex_first + 1) & 1023;
		}
	}
	if ((maddress >= 0x1880) && (maddress < 0x1900))
	{
		int v = maddress - 0x1880; // 16 couples,2 float per couple,16*2*4=128
		int attr = v >> 3;
		int comp = (v >> 2) & 1;

		persistvertexattr.attribute[attr].iv[comp] = data;
		if (comp == 1)
		{
			persistvertexattr.attribute[attr].fv[2] = 0;
			persistvertexattr.attribute[attr].fv[3] = 1;
			if (attr == 0)
				assemble_primitive(&persistvertexattr, 1, render_spans_callback);
		}
	}
	if ((maddress >= 0x1900) && (maddress < 0x1940))
	{
		int v = maddress - 0x1900; // 16 dwords,2 values per dword
		int attr = v >> 2;
		uint16_t d1 = data & 0xffff;
		uint16_t d2 = data >> 16;

		persistvertexattr.attribute[attr].fv[0] = (float)((int16_t)d1);
		persistvertexattr.attribute[attr].fv[1] = (float)((int16_t)d2);
		persistvertexattr.attribute[attr].fv[2] = 0;
		persistvertexattr.attribute[attr].fv[3] = 1;
		if (attr == 0)
			assemble_primitive(&persistvertexattr, 1, render_spans_callback);
	}
	if ((maddress >= 0x1940) && (maddress < 0x1980))
	{
		int v = maddress - 0x1940; // 16 dwords,4 values per dword
		int attr = v >> 2;
		uint8_t d1 = data & 255;
		uint8_t d2 = (data >> 8) & 255;
		uint8_t d3 = (data >> 16) & 255;
		uint8_t d4 = data >> 24;

		persistvertexattr.attribute[attr].fv[0] = (float)d1;
		persistvertexattr.attribute[attr].fv[1] = (float)d2;
		persistvertexattr.attribute[attr].fv[2] = (float)d3;
		persistvertexattr.attribute[attr].fv[3] = (float)d4;
		if (attr == 0)
			assemble_primitive(&persistvertexattr, 1, render_spans_callback);
	}
	if ((maddress >= 0x1980) && (maddress < 0x1a00))
	{
		int v = maddress - 0x1980; // 16 couples,4 values per couple,16*2*4=128
		int attr = v >> 3;
		int comp = (v >> 1) & 2;
		uint16_t d1 = data & 0xffff;
		uint16_t d2 = data >> 16;

		persistvertexattr.attribute[attr].fv[comp] = (float)((int16_t)d1);
		persistvertexattr.attribute[attr].fv[comp+1] = (float)((int16_t)d2);
		if (comp == 2)
			if (attr == 0)
				assemble_primitive(&persistvertexattr, 1, render_spans_callback);
	}
	if ((maddress >= 0x1a00) && (maddress < 0x1b00))
	{
		int v = maddress - 0x1a00; // 16 groups,4 float per group
		int attr = v >> 4;
		int comp = (v >> 2) & 3;

		persistvertexattr.attribute[attr].iv[comp] = data;
		if (comp == 3)
			if (attr == 0)
				assemble_primitive(&persistvertexattr, 1, render_spans_callback);
	}
	if ((maddress >= 0x1518) && (maddress < 0x1528))
	{
		int v = maddress - 0x1518;
		int comp = v >> 2;

		persistvertexattr.attribute[(int)NV2A_VERTEX_ATTR::POS].iv[comp] = data;
		if (comp == 3)
			assemble_primitive(&persistvertexattr, 1, render_spans_callback);
	}
	if ((maddress >= 0x1720) && (maddress < 0x1760)) {
		int bit = method - 0x1720 / 4;

		if (data & 0x80000000)
			vertexbuffer_address[bit] = (data & 0x0fffffff) + dma_offset[1];
		else
			vertexbuffer_address[bit] = (data & 0x0fffffff) + dma_offset[0];
	}
	if ((maddress >= 0x1760) && (maddress < 0x17A0)) {
		int bit = method - 0x1760 / 4;

		vertexbuffer_stride[bit] = (data >> 8) & 255;
		vertexbuffer_kind[bit] = (NV2A_VTXBUF_TYPE)(data & 15);
		vertexbuffer_size[bit] = (data >> 4) & 15;
		switch (vertexbuffer_kind[bit]) {
		case NV2A_VTXBUF_TYPE::UBYTE_D3D:
			vertex_attribute_words[bit] = (vertexbuffer_size[bit] * 1) >> 2;
			break;
		case NV2A_VTXBUF_TYPE::FLOAT:
			vertex_attribute_words[bit] = (vertexbuffer_size[bit] * 4) >> 2;
			break;
		case NV2A_VTXBUF_TYPE::UBYTE_OGL:
			vertex_attribute_words[bit] = (vertexbuffer_size[bit] * 1) >> 2;
			break;
		case NV2A_VTXBUF_TYPE::USHORT:
			vertex_attribute_words[bit] = (vertexbuffer_size[bit] * 2) >> 2;
			break;
		case NV2A_VTXBUF_TYPE::FLOAT_PACKED:
			vertex_attribute_words[bit] = (vertexbuffer_size[bit] * 4) >> 2;
			break;
		default:
			vertex_attribute_words[bit] = 0;
		}
		if (vertexbuffer_size[bit] > 0)
			enabled_vertex_attributes |= (1 << bit);
		else
			enabled_vertex_attributes &= ~(1 << bit);
		for (int n = bit + 1; n < 16; n++) {
			if ((enabled_vertex_attributes & (1 << (n - 1))) != 0)
				vertex_attribute_offset[n] = vertex_attribute_offset[n - 1] + vertex_attribute_words[n - 1];
			else
				vertex_attribute_offset[n] = vertex_attribute_offset[n - 1];
		}
		countlen--;
	}
	if ((maddress == 0x1d6c) || (maddress == 0x1a4))
		countlen--;
	if (maddress == 0x0308) {
		backface_culling_enabled = data != 0 ? true : false;
	}
	if (maddress == 0x03a0) {
		backface_culling_winding = (NV2A_GL_FRONT_FACE)data;
	}
	if (maddress == 0x039c) {
		backface_culling_culled = (NV2A_GL_CULL_FACE)data;
	}
	if (maddress == 0x019c) {
		geforce_read_dma_object(data, dma_offset[0], dma_size[0]);
	}
	if (maddress == 0x01a0) {
		geforce_read_dma_object(data, dma_offset[1], dma_size[1]);
	}
	if (maddress == 0x1d70) {
		// with 1d70 write the value at offest [1d6c] inside dma object [1a4]
		uint32_t offset, base;
		uint32_t dmahand, dmaoff, smasiz;

		offset = channel[chanel][subchannel].object.method[0x1d6c / 4];
		dmahand = channel[chanel][subchannel].object.method[0x1a4 / 4];
		geforce_read_dma_object(dmahand, dmaoff, smasiz);
		base = dmaoff;
		space.write_dword(base + offset, data);
		// software expects to find the parameter of this method at pgraph offset b10
		pgraph[0xb10 / 4] = data << 2;
		countlen--;
	}
	if (maddress == 0x1d7c) {
		antialias_control = data;
		compute_supersample_factors(supersample_factor_x, supersample_factor_y);
		compute_limits_rendertarget(chanel, subchannel);
		countlen--;
	}
	if (maddress == 0x1d98) {
		int x, w;

		x = data & 0xffff;
		w = (data >> 16) & 0xffff;
		clear_rendertarget.setx(x, w);
		countlen--;
	}
	if (maddress == 0x1d9c) {
		int y, h;

		y = data & 0xffff;
		h = (data >> 16) & 0xffff;
		clear_rendertarget.sety(y, h);
		countlen--;
	}
	if (maddress == 0x1d94) {
		// possible buffers: color, depth, stencil
		// clear framebuffer
		clear_render_target((data >> 4) & 15, channel[chanel][subchannel].object.method[0x1d90 / 4]);
		clear_depth_buffer(data & 3, channel[chanel][subchannel].object.method[0x1d8c / 4]);
		countlen--;
	}
	if ((maddress >= 0x02c0) && (maddress < 0x2e0)) {
		int x, w, i;

		i = (maddress - 0x2c0) / 4;
		x = data & 0xffff;
		w = (data >> 16) & 0xffff;
		clippingwindows[i].setx(x, x + w - 1);
	}
	if ((maddress >= 0x02e0) && (maddress < 0x300)) {
		int y, h, i;

		i = (maddress - 0x2e0) / 4;
		y = data & 0xffff;
		h = (data >> 16) & 0xffff;
		clippingwindows[i].sety(y, y + h - 1);
	}
	if (maddress == 0x0200) {
		compute_limits_rendertarget(chanel, subchannel);
		compute_size_rendertarget(chanel, subchannel);
	}
	if (maddress == 0x0204) {
		compute_limits_rendertarget(chanel, subchannel);
		compute_size_rendertarget(chanel, subchannel);
	}
	if (maddress == 0x0208) {
		log2height_rendertarget = (data >> 24) & 255;
		log2width_rendertarget = (data >> 16) & 255;
		antialiasing_rendertarget = (data >> 12) & 15;
		type_rendertarget = (NV2A_RT_TYPE)((data >> 8) & 15);
		depthformat_rendertarget = (NV2A_RT_DEPTH_FORMAT)((data >> 4) & 15);
		colorformat_rendertarget = (NV2A_COLOR_FORMAT)((data >> 0) & 15);
		compute_supersample_factors(supersample_factor_x, supersample_factor_y);
		compute_limits_rendertarget(chanel, subchannel);
		compute_size_rendertarget(chanel, subchannel);
		switch (colorformat_rendertarget) {
		case NV2A_COLOR_FORMAT::R5G6B5:
			bytespixel_rendertarget = 2;
			break;
		case NV2A_COLOR_FORMAT::X8R8G8B8_Z8R8G8B8:
		case NV2A_COLOR_FORMAT::X8R8G8B8_X8R8G8B8:
		case NV2A_COLOR_FORMAT::A8R8G8B8:
			bytespixel_rendertarget = 4;
			break;
		case NV2A_COLOR_FORMAT::B8:
			bytespixel_rendertarget = 1;
			break;
		default:
			machine().logerror("Unknown render target color format %d\n\r", int(colorformat_rendertarget));
			bytespixel_rendertarget = 4;
			break;
		}
		dilate_rendertarget = dilatechose[(log2width_rendertarget << 4) + log2height_rendertarget];
	}
	if (maddress == 0x020c) {
		pitch_rendertarget=data & 0xffff;
		pitch_depthbuffer=(data >> 16) & 0xffff;
		compute_size_rendertarget(chanel, subchannel);
#ifdef LOG_NV2A
		printf("Pitch color %04X zbuffer %04X\n\r", pitch_rendertarget, pitch_depthbuffer);
#endif
		countlen--;
	}
	if (maddress == 0x0100) {
		countlen--;
		if (data != 0) {
			pgraph[0x704 / 4] = 0x100;
			pgraph[0x708 / 4] = data;
			pgraph[0x100 / 4] |= 1;
			pgraph[0x108 / 4] |= 1;
			if (update_interrupts() == true)
				irq_callback(1); // IRQ 3
			else
				irq_callback(0); // IRQ 3
			return 2;
		}
		else
			return 0;
	}
	if (maddress == 0x0130) {
		countlen--;
		if (enable_waitvblank == true)
			return 1; // block until next vblank
		else
			return 0;
	}
	if (maddress == 0x1d8c) {
		countlen--;
		// it is used to specify the clear value for the depth buffer (zbuffer)
		// but also as a parameter for interrupt routines
		pgraph[0x1a88 / 4] = data;
	}
	if (maddress == 0x1d90) {
		countlen--;
		// it is used to specify the clear value for the color buffer
		// but also as a parameter for interrupt routines
		pgraph[0x186c / 4] = data;
	}
	if (maddress == 0x0210) {
		// framebuffer offset ?
		rendertarget = (uint32_t *)direct_access_ptr(data);
#ifdef LOG_NV2A
		printf("Render target at %08X\n\r", data);
#endif
		countlen--;
	}
	if (maddress == 0x0214) {
		// zbuffer offset ?
		depthbuffer = (uint32_t *)direct_access_ptr(data);
#ifdef LOG_NV2A
		printf("Depth buffer at %08X\n\r",data);
#endif
		if ((data == 0) || (data > 0x7ffffffc))
			depth_write_enabled = false;
		else if (channel[chanel][subchannel].object.method[0x035c / 4] != 0)
			depth_write_enabled = true;
		else
			depth_write_enabled = false;
		countlen--;
	}
	if (maddress == 0x0300) {
		alpha_test_enabled = data != 0;
	}
	if (maddress == 0x033c) {
		alpha_func = (NV2A_COMPARISON_OP)data;
	}
	if (maddress == 0x0340) {
		alpha_reference = data;
	}
	if (maddress == 0x0304) {
		if (logical_operation_enabled)
			blending_enabled = false;
		else
			blending_enabled = data != 0;
	}
	if (maddress == 0x030c) {
		depth_test_enabled = data != 0;
	}
	if (maddress == 0x0354) {
		depth_function = (NV2A_COMPARISON_OP)data;
	}
	if (maddress == 0x0358) {
		//color_mask = data;
		if (data & 0x000000ff)
			data |= 0x000000ff;
		if (data & 0x0000ff00)
			data |= 0x0000ff00;
		if (data & 0x00ff0000)
			data |= 0x00ff0000;
		if (data & 0xff000000)
			data |= 0xff000000;
		color_mask = data;
	}
	if (maddress == 0x035c) {
		uint32_t g = channel[chanel][subchannel].object.method[0x0214 / 4];
		depth_write_enabled = data != 0;
		if ((g == 0) || (g > 0x7ffffffc))
			depth_write_enabled = false;
	}
	if (maddress == 0x032c) {
		stencil_test_enabled = data != 0;
	}
	if (maddress == 0x0364) {
		stencil_func = (NV2A_COMPARISON_OP)data;
	}
	if (maddress == 0x0368) {
		if (data > 255)
			data = 255;
		stencil_ref = data;
	}
	if (maddress == 0x036c) {
		stencil_mask = data;
	}
	if (maddress == 0x0370) {
		stencil_op_fail = (NV2A_STENCIL_OP)data;
	}
	if (maddress == 0x0374) {
		stencil_op_zfail = (NV2A_STENCIL_OP)data;
	}
	if (maddress == 0x0378) {
		stencil_op_zpass = (NV2A_STENCIL_OP)data;
	}
	if (maddress == 0x0344) {
		blend_function_source = (NV2A_BLEND_FACTOR)data;
	}
	if (maddress == 0x0348) {
		blend_function_destination = (NV2A_BLEND_FACTOR)data;
	}
	if (maddress == 0x034c) {
		blend_color = data;
	}
	if (maddress == 0x0350) {
		blend_equation = (NV2A_BLEND_EQUATION)data;
	}
	if (maddress == 0x0d40) {
		if (data != 0)
			blending_enabled = false;
		else
			blending_enabled = channel[chanel][subchannel].object.method[0x0304 / 4] != 0;
		logical_operation_enabled = data != 0;
	}
	if (maddress == 0x0d44) {
		logical_operation = (NV2A_LOGIC_OP)data;
	}
	// Texture Units
	if ((maddress >= 0x1b00) && (maddress < 0x1c00)) {
		int unit;//,off;

		unit = (maddress >> 6) & 3;
		//off=maddress & 0xc0;
		maddress = maddress & ~0xc0;
		if (maddress == 0x1b00) {
			uint32_t offset;//,base;
			//uint32_t dmahand,dmaoff,dmasiz;

			offset = data;
			texture[unit].buffer = direct_access_ptr(offset);
			/*if (dma0 != 0) {
			dmahand=channel[channel][subchannel].object.method[0x184/4];
			geforce_read_dma_object(dmahand,dmaoff,smasiz);
			} else if (dma1 != 0) {
			dmahand=channel[channel][subchannel].object.method[0x188/4];
			geforce_read_dma_object(dmahand,dmaoff,smasiz);
			}*/
		}
		if (maddress == 0x1b04) {
			int basesizeu, basesizev, basesizew, format;
			bool rectangle;

			texture[unit].dma0 = (data >> 0) & 1;
			texture[unit].dma1 = (data >> 1) & 1;
			texture[unit].cubic = (data >> 2) & 1;
			texture[unit].noborder = (data >> 3) & 1;
			texture[unit].dims = (data >> 4) & 15;
			texture[unit].mipmap = (data >> 19) & 1;
			format = (data >> 8) & 255;
			basesizeu = (data >> 20) & 15;
			basesizev = (data >> 24) & 15;
			basesizew = (data >> 28) & 15;
			texture[unit].sizeu = 1 << basesizeu;
			texture[unit].sizev = 1 << basesizev;
			texture[unit].sizew = 1 << basesizew;
			texture[unit].dilate = dilatechose[(basesizeu << 4) + basesizev];
			texture[unit].format = (NV2A_TEX_FORMAT)format;
			switch (texture[unit].format)
			{
			case NV2A_TEX_FORMAT::A1R5G5B5_RECT:
			case NV2A_TEX_FORMAT::R5G6B5_RECT:
			case NV2A_TEX_FORMAT::A8R8G8B8_RECT:
			case NV2A_TEX_FORMAT::DSDT8_RECT:
			case NV2A_TEX_FORMAT::A4R4G4B4_RECT:
			case NV2A_TEX_FORMAT::R8G8B8_RECT:
			case NV2A_TEX_FORMAT::A8L8_RECT:
			case NV2A_TEX_FORMAT::Z24_RECT:
			case NV2A_TEX_FORMAT::Z16_RECT:
			case NV2A_TEX_FORMAT::HILO16_RECT:
			case NV2A_TEX_FORMAT::SIGNED_HILO8_RECT:
				rectangle = true;
				break;
			default:
				rectangle = false;
			}
			texture[unit].rectangle = rectangle;
			if (debug_grab_texttype == format) {
				FILE *f;
				int written;

				debug_grab_texttype = -1;
				f = fopen(debug_grab_textfile, "wb");
				if (f) {
					written = (int)fwrite(texture[unit].buffer, texture[unit].sizeu*texture[unit].sizev * 4, 1, f);
					fclose(f);
					machine().logerror("Written %d bytes of texture to specified file\n", written);
				}
				else
					machine().logerror("Unable to save texture to specified file\n");
			}
		}
		/*if (maddress == 0x1b08) {
		    (data >> 0) & 15;
		    (data >> 4) & 15;
		    (data >> 8) & 15;
		    (data >> 12) & 15;
		    (data >> 16) & 15;
		    (data >> 20) & 15;
		    (data >> 24) & 255;
		}*/
		if (maddress == 0x1b0c) {
			texture[unit].colorkey = (data >> 0) & 3;
			texture[unit].imagefield = (data >> 3) & 1;
			texture[unit].aniso = (data >> 4) & 3;
			texture[unit].mipmapmaxlod = (data >> 6) & 0xfff;
			texture[unit].mipmapminlod = (data >> 18) & 0xfff;
			// enable texture
			texture[unit].enabled = (data >> 30) & 3;
		}
		if (maddress == 0x1b10) {
			texture[unit].rectangle_pitch = data >> 16;
		}
		if (maddress == 0x1b1c) {
			texture[unit].rectheight = data & 0xffff;
			texture[unit].rectwidth = data >> 16;
		}
		countlen--;
	}
	// projection matrix
	if ((maddress >= 0x0440) && (maddress < 0x0480)) {
		maddress = (maddress - 0x0440) / 4;
		*(uint32_t *)(&matrix.projection[maddress >> 2][maddress & 3]) = data;
		countlen--;
	}
	// modelview matrix
	if ((maddress >= 0x0480) && (maddress < 0x04c0)) {
		maddress = (maddress - 0x0480) / 4;
		/* the modelview matrix is obtained by direct3d by multiplying the world matrix and the view matrix
		    modelview = world * view
		   given a point in 3d space with coordinates x y and z, to find te transformed coordinates
		   first create a row vector with components (x,y,z,1) then multiply the vector by the matrix
		    transformed = rowvector * matrix
		   in direct3d the matrix is stored as the sequence (first digit row, second digit column)
		    11 12 13 14
		    21 22 23 24
		    31 32 33 34
		    41 42 43 44
		   but it is sent transposed as the sequence
		    11 21 31 41 12 22 32 42 13 23 33 43 14 24 34 44
		   so in matrix.modelview[x][y] x is the column and y is the row of the direct3d matrix
		*/
		*(uint32_t *)(&matrix.modelview[maddress >> 2][maddress & 3]) = data;
		countlen--;
	}
	// inverse modelview matrix
	if ((maddress >= 0x0580) && (maddress < 0x05c0)) {
		maddress = (maddress - 0x0580) / 4;
		*(uint32_t *)(&matrix.modelview_inverse[maddress >> 2][maddress & 3]) = data;
		countlen--;
	}
	// composite matrix
	if ((maddress >= 0x0680) && (maddress < 0x06c0)) {
		maddress = (maddress - 0x0680) / 4;
		/* the composite matrix is computed by direct3d by multiplying the
		   world, view, projection and viewport matrices
		    composite = world * view * projection * viewport
		   the viewport matrix applies the viewport scale and offset
		 */
		*(uint32_t *)(&matrix.composite[maddress >> 2][maddress & 3]) = data;
		countlen--;
	}
	// viewport translate
	if ((maddress >= 0x0a20) && (maddress < 0x0a30)) {
		maddress = (maddress - 0x0a20) / 4;
		*(uint32_t *)(&matrix.translate[maddress]) = data;
		// set corresponding vertex shader constant too
		vertexprogram.exec.c_constant[59].iv(maddress, data); // constant -37
#ifdef LOG_NV2A
		if (maddress == 3)
			machine().logerror("viewport translate = {%f %f %f %f}\n", matrix.translate[0], matrix.translate[1], matrix.translate[2], matrix.translate[3]);
#endif
		countlen--;
	}
	// viewport scale
	if ((maddress >= 0x0af0) && (maddress < 0x0b00)) {
		maddress = (maddress - 0x0af0) / 4;
		*(uint32_t *)(&matrix.scale[maddress]) = data;
		// set corresponding vertex shader constant too
		vertexprogram.exec.c_constant[58].iv(maddress, data); // constant -38
#ifdef LOG_NV2A
		if (maddress == 3)
			machine().logerror("viewport scale = {%f %f %f %f}\n", matrix.scale[0], matrix.scale[1], matrix.scale[2], matrix.scale[3]);
#endif
		countlen--;
	}
	// Vertex program (shader)
	if (maddress == 0x1e94) {
		/*if (data == 2)
		machine().logerror("Enabled vertex program\n");
		else if (data == 4)
		machine().logerror("Enabled fixed function pipeline\n");
		else if (data == 6)
		machine().logerror("Enabled both fixed function pipeline and vertex program ?\n");
		else
		machine().logerror("Unknown value %d to method 0x1e94\n",data);*/
		vertex_pipeline = data & 6;
		countlen--;
	}
	if (maddress == 0x1e9c) {
		//machine().logerror("VP_UPLOAD_FROM_ID %d\n",data);
		vertexprogram.upload_instruction_index = data;
		vertexprogram.upload_instruction_component = 0;
		countlen--;
	}
	if (maddress == 0x1ea0) {
		//machine().logerror("VP_START_FROM_ID %d\n",data);
		vertexprogram.instructions = vertexprogram.upload_instruction_index;
		vertexprogram.start_instruction = data;
		countlen--;
	}
	if (maddress == 0x1ea4) {
		//machine().logerror("VP_UPLOAD_CONST_ID %d\n",data);
		vertexprogram.upload_parameter_index = data;
		vertexprogram.upload_parameter_component = 0;
		countlen--;
	}
	if ((maddress >= 0x0b00) && (maddress < 0x0b80)) {
		//machine().logerror("VP_UPLOAD_INST\n");
		if (vertexprogram.upload_instruction_index < 256) {
			vertexprogram.exec.op[vertexprogram.upload_instruction_index].i[vertexprogram.upload_instruction_component] = data;
			vertexprogram.exec.op[vertexprogram.upload_instruction_index].modified |= (1 << vertexprogram.upload_instruction_component);
		}
		else
			machine().logerror("Need to increase size of vertexprogram.instruction to %d\n\r", vertexprogram.upload_instruction_index);
		if (vertexprogram.exec.op[vertexprogram.upload_instruction_index].modified == 15) {
			vertexprogram.exec.op[vertexprogram.upload_instruction_index].modified = 0;
			vertexprogram.exec.decode_instruction(vertexprogram.upload_instruction_index);
		}
		vertexprogram.upload_instruction_component++;
		if (vertexprogram.upload_instruction_component >= 4) {
			vertexprogram.upload_instruction_component = 0;
			vertexprogram.upload_instruction_index++;
		}
	}
	if ((maddress >= 0x0b80) && (maddress < 0x0c00)) {
		//machine().logerror("VP_UPLOAD_CONST\n");
		if (vertexprogram.upload_parameter_index < 192) {
			vertexprogram.exec.c_constant[vertexprogram.upload_parameter_index].iv(vertexprogram.upload_parameter_component, data);
		}
		else
			machine().logerror("Need to increase size of vertexprogram.parameter to %d\n\r", vertexprogram.upload_parameter_index);
		vertexprogram.upload_parameter_component++;
		if (vertexprogram.upload_parameter_component >= 4) {
#ifdef LOG_NV2A
			if ((vertexprogram.upload_parameter_index == 58) || (vertexprogram.upload_parameter_index == 59))
				machine().logerror("vp constant %d (%s) = {%f %f %f %f}\n", vertexprogram.upload_parameter_index,
					vertexprogram.upload_parameter_index == 58 ? "viewport scale" : "viewport translate",
					vertexprogram.exec.c_constant[vertexprogram.upload_parameter_index].fv[0],
					vertexprogram.exec.c_constant[vertexprogram.upload_parameter_index].fv[1],
					vertexprogram.exec.c_constant[vertexprogram.upload_parameter_index].fv[2],
					vertexprogram.exec.c_constant[vertexprogram.upload_parameter_index].fv[3]);
#endif
			vertexprogram.upload_parameter_component = 0;
			vertexprogram.upload_parameter_index++;
		}
	}
	// Register combiners
	if (maddress == 0x1e60) {
		combiner.stages = data & 15;
		countlen--;
	}
	if (maddress == 0x0288) {
		combiner.final.mapin_rgbD_input = data & 15;
		combiner.final.mapin_rgbD_component = (data >> 4) & 1;
		combiner.final.mapin_rgbD_mapping = (data >> 5) & 7;
		combiner.final.mapin_rgbC_input = (data >> 8) & 15;
		combiner.final.mapin_rgbC_component = (data >> 12) & 1;
		combiner.final.mapin_rgbC_mapping = (data >> 13) & 7;
		combiner.final.mapin_rgbB_input = (data >> 16) & 15;
		combiner.final.mapin_rgbB_component = (data >> 20) & 1;
		combiner.final.mapin_rgbB_mapping = (data >> 21) & 7;
		combiner.final.mapin_rgbA_input = (data >> 24) & 15;
		combiner.final.mapin_rgbA_component = (data >> 28) & 1;
		combiner.final.mapin_rgbA_mapping = (data >> 29) & 7;
		countlen--;
	}
	if (maddress == 0x028c) {
		combiner.final.color_sum_clamp = (data >> 7) & 1;
		combiner.final.mapin_aG_input = (data >> 8) & 15;
		combiner.final.mapin_aG_component = (data >> 12) & 1;
		combiner.final.mapin_aG_mapping = (data >> 13) & 7;
		combiner.final.mapin_rgbF_input = (data >> 16) & 15;
		combiner.final.mapin_rgbF_component = (data >> 20) & 1;
		combiner.final.mapin_rgbF_mapping = (data >> 21) & 7;
		combiner.final.mapin_rgbE_input = (data >> 24) & 15;
		combiner.final.mapin_rgbE_component = (data >> 28) & 1;
		combiner.final.mapin_rgbE_mapping = (data >> 29) & 7;
		countlen--;
	}
	if (maddress == 0x1e20) {
		combiner_argb8_float(data, combiner.final.register_constantcolor0);
		countlen--;
	}
	if (maddress == 0x1e24) {
		combiner_argb8_float(data, combiner.final.register_constantcolor1);
		countlen--;
	}
	if ((maddress >= 0x0260) && (maddress < 0x0280)) {
		int n;

		n = (maddress - 0x0260) >> 2;
		combiner.stage[n].mapin_aD_input = data & 15;
		combiner.stage[n].mapin_aD_component = (data >> 4) & 1;
		combiner.stage[n].mapin_aD_mapping = (data >> 5) & 7;
		combiner.stage[n].mapin_aC_input = (data >> 8) & 15;
		combiner.stage[n].mapin_aC_component = (data >> 12) & 1;
		combiner.stage[n].mapin_aC_mapping = (data >> 13) & 7;
		combiner.stage[n].mapin_aB_input = (data >> 16) & 15;
		combiner.stage[n].mapin_aB_component = (data >> 20) & 1;
		combiner.stage[n].mapin_aB_mapping = (data >> 21) & 7;
		combiner.stage[n].mapin_aA_input = (data >> 24) & 15;
		combiner.stage[n].mapin_aA_component = (data >> 28) & 1;
		combiner.stage[n].mapin_aA_mapping = (data >> 29) & 7;
		countlen--;
	}
	if ((maddress >= 0x0ac0) && (maddress < 0x0ae0)) {
		int n;

		n = (maddress - 0x0ac0) >> 2;
		combiner.stage[n].mapin_rgbD_input = data & 15;
		combiner.stage[n].mapin_rgbD_component = (data >> 4) & 1;
		combiner.stage[n].mapin_rgbD_mapping = (data >> 5) & 7;
		combiner.stage[n].mapin_rgbC_input = (data >> 8) & 15;
		combiner.stage[n].mapin_rgbC_component = (data >> 12) & 1;
		combiner.stage[n].mapin_rgbC_mapping = (data >> 13) & 7;
		combiner.stage[n].mapin_rgbB_input = (data >> 16) & 15;
		combiner.stage[n].mapin_rgbB_component = (data >> 20) & 1;
		combiner.stage[n].mapin_rgbB_mapping = (data >> 21) & 7;
		combiner.stage[n].mapin_rgbA_input = (data >> 24) & 15;
		combiner.stage[n].mapin_rgbA_component = (data >> 28) & 1;
		combiner.stage[n].mapin_rgbA_mapping = (data >> 29) & 7;
		countlen--;
	}
	if ((maddress >= 0x0a60) && (maddress < 0x0a80)) {
		int n;

		n = (maddress - 0x0a60) >> 2;
		combiner_argb8_float(data, combiner.stage[n].register_constantcolor0);
		countlen--;
	}
	if ((maddress >= 0x0a80) && (maddress < 0x0aa0)) {
		int n;

		n = (maddress - 0x0a80) >> 2;
		combiner_argb8_float(data, combiner.stage[n].register_constantcolor1);
		countlen--;
	}
	if ((maddress >= 0x0aa0) && (maddress < 0x0ac0)) {
		int n;

		n = (maddress - 0x0aa0) >> 2;
		combiner.stage[n].mapout_aCD_output = data & 15;
		combiner.stage[n].mapout_aAB_output = (data >> 4) & 15;
		combiner.stage[n].mapout_aSUM_output = (data >> 8) & 15;
		combiner.stage[n].mapout_aCD_dotproduct = (data >> 12) & 1;
		combiner.stage[n].mapout_aAB_dotproduct = (data >> 13) & 1;
		combiner.stage[n].mapout_a_muxsum = (data >> 14) & 1;
		combiner.stage[n].mapout_a_bias = (data >> 15) & 1;
		combiner.stage[n].mapout_a_scale = (data >> 16) & 3;
		//combiner.=(data >> 27) & 7;
		countlen--;
	}
	if ((maddress >= 0x1e40) && (maddress < 0x1e60)) {
		int n;

		n = (maddress - 0x1e40) >> 2;
		combiner.stage[n].mapout_rgbCD_output = data & 15;
		combiner.stage[n].mapout_rgbAB_output = (data >> 4) & 15;
		combiner.stage[n].mapout_rgbSUM_output = (data >> 8) & 15;
		combiner.stage[n].mapout_rgbCD_dotproduct = (data >> 12) & 1;
		combiner.stage[n].mapout_rgbAB_dotproduct = (data >> 13) & 1;
		combiner.stage[n].mapout_rgb_muxsum = (data >> 14) & 1;
		combiner.stage[n].mapout_rgb_bias = (data >> 15) & 1;
		combiner.stage[n].mapout_rgb_scale = (data >> 16) & 3;
		//combiner.=(data >> 27) & 7;
		countlen--;
	}
	return 0;
}

bool nv2a_renderer::toggle_register_combiners_usage()
{
	combiner.used = 1 - combiner.used;
	return combiner.used != 0;
}

bool nv2a_renderer::toggle_wait_vblank_support()
{
	enable_waitvblank = !enable_waitvblank;
	return enable_waitvblank;
}

bool nv2a_renderer::toggle_clipping_w_support()
{
	enable_clipping_w = !enable_clipping_w;
	return enable_clipping_w;
}

void nv2a_renderer::debug_grab_texture(int type, const char *filename)
{
	debug_grab_texttype = type;
	if (debug_grab_textfile == nullptr)
		debug_grab_textfile = (char *)malloc(128);
	strncpy(debug_grab_textfile, filename, 127);
}

void nv2a_renderer::debug_grab_vertex_program_slot(int slot, uint32_t *instruction)
{
	if (slot >= 1024 / 4)
		return;
	instruction[0] = vertexprogram.exec.op[slot].i[0];
	instruction[1] = vertexprogram.exec.op[slot].i[1];
	instruction[2] = vertexprogram.exec.op[slot].i[2];
	instruction[3] = vertexprogram.exec.op[slot].i[3];
}

void nv2a_renderer::combiner_argb8_float(uint32_t color, float reg[4])
{
	reg[0] = (float)(color & 0xff) / 255.0f;
	reg[1] = (float)((color >> 8) & 0xff) / 255.0f;
	reg[2] = (float)((color >> 16) & 0xff) / 255.0f;
	reg[3] = (float)((color >> 24) & 0xff) / 255.0f;
}

uint32_t nv2a_renderer::combiner_float_argb8(float reg[4])
{
	uint32_t r, g, b, a;

	a = reg[3] * 255.0f;
	r = reg[2] * 255.0f;
	g = reg[1] * 255.0f;
	b = reg[0] * 255.0f;
	return (a << 24) | (r << 16) | (g << 8) | b;
}

float nv2a_renderer::combiner_map_input_select(int code, int index)
{
	switch (code) {
	case 0:
	default:
		return combiner.register_zero[index];
	case 1:
		return combiner.register_color0[index];
	case 2:
		return combiner.register_color1[index];
	case 3:
		return combiner.register_fogcolor[index];
	case 4:
		return combiner.register_primarycolor[index];
	case 5:
		return combiner.register_secondarycolor[index];
	case 8:
		return combiner.register_texture0color[index];
	case 9:
		return combiner.register_texture1color[index];
	case 10:
		return combiner.register_texture2color[index];
	case 11:
		return combiner.register_texture3color[index];
	case 12:
		return combiner.register_spare0[index];
	case 13:
		return combiner.register_spare1[index];
	case 14:
		return combiner.variable_sumclamp[index];
	case 15:
		return combiner.variable_EF[index];
	}

	// never executed
	//return 0;
}

float *nv2a_renderer::combiner_map_input_select3(int code)
{
	switch (code) {
	case 0:
	default:
		return combiner.register_zero;
	case 1:
		return combiner.register_color0;
	case 2:
		return combiner.register_color1;
	case 3:
		return combiner.register_fogcolor;
	case 4:
		return combiner.register_primarycolor;
	case 5:
		return combiner.register_secondarycolor;
	case 8:
		return combiner.register_texture0color;
	case 9:
		return combiner.register_texture1color;
	case 10:
		return combiner.register_texture2color;
	case 11:
		return combiner.register_texture3color;
	case 12:
		return combiner.register_spare0;
	case 13:
		return combiner.register_spare1;
	case 14:
		return combiner.variable_sumclamp;
	case 15:
		return combiner.variable_EF;
	}

	// never executed
	//return 0;
}

float *nv2a_renderer::combiner_map_output_select3(int code)
{
	switch (code) {
	case 0:
		return nullptr;
	case 1:
		return nullptr;
	case 2:
		return nullptr;
	case 3:
		return nullptr;
	case 4:
		return combiner.register_primarycolor;
	case 5:
		return combiner.register_secondarycolor;
	case 8:
		return combiner.register_texture0color;
	case 9:
		return combiner.register_texture1color;
	case 10:
		return combiner.register_texture2color;
	case 11:
		return combiner.register_texture3color;
	case 12:
		return combiner.register_spare0;
	case 13:
		return combiner.register_spare1;
	case 14:
		return nullptr;
	case 15:
	default:
		return nullptr;
	}
}

float nv2a_renderer::combiner_map_input_function(int code, float value)
{
	float t;

	switch (code) {
	case 0:
		return std::max(0.0f, value);
	case 1:
		t = std::max(value, 0.0f);
		return 1.0f - std::min(t, 1.0f);
	case 2:
		return 2.0f * std::max(0.0f, value) - 1.0f;
	case 3:
		return -2.0f * std::max(0.0f, value) + 1.0f;
	case 4:
		return std::max(0.0f, value) - 0.5f;
	case 5:
		return -std::max(0.0f, value) + 0.5f;
	case 6:
		return value;
	case 7:
	default:
		return -value;
	}

	// never executed
	//return 0;
}

void nv2a_renderer::combiner_map_input_function3(int code, float *data)
{
	float t;

	switch (code) {
	case 0:
		data[0] = std::max(0.0f, data[0]);
		data[1] = std::max(0.0f, data[1]);
		data[2] = std::max(0.0f, data[2]);
		break;
	case 1:
		t = std::max(data[0], 0.0f);
		data[0] = 1.0f - std::min(t, 1.0f);
		t = std::max(data[1], 0.0f);
		data[1] = 1.0f - std::min(t, 1.0f);
		t = std::max(data[2], 0.0f);
		data[2] = 1.0f - std::min(t, 1.0f);
		break;
	case 2:
		data[0] = 2.0f * std::max(0.0f, data[0]) - 1.0f;
		data[1] = 2.0f * std::max(0.0f, data[1]) - 1.0f;
		data[2] = 2.0f * std::max(0.0f, data[2]) - 1.0f;
		break;
	case 3:
		data[0] = -2.0f * std::max(0.0f, data[0]) + 1.0f;
		data[1] = -2.0f * std::max(0.0f, data[1]) + 1.0f;
		data[2] = -2.0f * std::max(0.0f, data[2]) + 1.0f;
		break;
	case 4:
		data[0] = std::max(0.0f, data[0]) - 0.5f;
		data[1] = std::max(0.0f, data[1]) - 0.5f;
		data[2] = std::max(0.0f, data[2]) - 0.5f;
		break;
	case 5:
		data[0] = -std::max(0.0f, data[0]) + 0.5f;
		data[1] = -std::max(0.0f, data[1]) + 0.5f;
		data[2] = -std::max(0.0f, data[2]) + 0.5f;
		break;
	case 6:
		return;
	case 7:
	default:
		data[0] = -data[0];
		data[1] = -data[1];
		data[2] = -data[2];
		break;
	}
}

void nv2a_renderer::combiner_initialize_registers(uint32_t argb8[6])
{
	combiner_argb8_float(argb8[0], combiner.register_primarycolor);
	combiner_argb8_float(argb8[1], combiner.register_secondarycolor);
	combiner_argb8_float(argb8[2], combiner.register_texture0color);
	combiner_argb8_float(argb8[3], combiner.register_texture1color);
	combiner_argb8_float(argb8[4], combiner.register_texture2color);
	combiner_argb8_float(argb8[5], combiner.register_texture3color);
	combiner.register_spare0[3] = combiner.register_texture0color[3];
	combiner.register_zero[0] = combiner.register_zero[1] = combiner.register_zero[2] = combiner.register_zero[3] = 0;
}

void nv2a_renderer::combiner_initialize_stage(int stage_number)
{
	int n = stage_number;

	// put register_constantcolor0 in register_color0
	combiner.register_color0[0] = combiner.stage[n].register_constantcolor0[0];
	combiner.register_color0[1] = combiner.stage[n].register_constantcolor0[1];
	combiner.register_color0[2] = combiner.stage[n].register_constantcolor0[2];
	combiner.register_color0[3] = combiner.stage[n].register_constantcolor0[3];
	// put register_constantcolor1 in register_color1
	combiner.register_color1[0] = combiner.stage[n].register_constantcolor1[0];
	combiner.register_color1[1] = combiner.stage[n].register_constantcolor1[1];
	combiner.register_color1[2] = combiner.stage[n].register_constantcolor1[2];
	combiner.register_color1[3] = combiner.stage[n].register_constantcolor1[3];
}

void nv2a_renderer::combiner_initialize_final()
{
	// put register_constantcolor0 in register_color0
	combiner.register_color0[0] = combiner.final.register_constantcolor0[0];
	combiner.register_color0[1] = combiner.final.register_constantcolor0[1];
	combiner.register_color0[2] = combiner.final.register_constantcolor0[2];
	combiner.register_color0[3] = combiner.final.register_constantcolor0[3];
	// put register_constantcolor1 in register_color1
	combiner.register_color1[0] = combiner.final.register_constantcolor1[0];
	combiner.register_color1[1] = combiner.final.register_constantcolor1[1];
	combiner.register_color1[2] = combiner.final.register_constantcolor1[2];
	combiner.register_color1[3] = combiner.final.register_constantcolor1[3];
}

void nv2a_renderer::combiner_map_input(int stage_number)
{
	int n = stage_number;
	int c, d, i;
	float v, *pv;

	// A
	v = combiner_map_input_select(combiner.stage[n].mapin_aA_input, 2 + combiner.stage[n].mapin_aA_component);
	combiner.variable_A[3] = combiner_map_input_function(combiner.stage[n].mapin_aA_mapping, v);
	// B
	v = combiner_map_input_select(combiner.stage[n].mapin_aB_input, 2 + combiner.stage[n].mapin_aB_component);
	combiner.variable_B[3] = combiner_map_input_function(combiner.stage[n].mapin_aB_mapping, v);
	// C
	v = combiner_map_input_select(combiner.stage[n].mapin_aC_input, 2 + combiner.stage[n].mapin_aC_component);
	combiner.variable_C[3] = combiner_map_input_function(combiner.stage[n].mapin_aC_mapping, v);
	// D
	v = combiner_map_input_select(combiner.stage[n].mapin_aD_input, 2 + combiner.stage[n].mapin_aD_component);
	combiner.variable_D[3] = combiner_map_input_function(combiner.stage[n].mapin_aD_mapping, v);

	// A
	pv = combiner_map_input_select3(combiner.stage[n].mapin_rgbA_input);
	c = combiner.stage[n].mapin_rgbA_component * 3;
	i = ~combiner.stage[n].mapin_rgbA_component & 1;
	for (d = 0; d < 3; d++) {
		combiner.variable_A[d] = pv[c];
		c = c + i;
	}
	combiner_map_input_function3(combiner.stage[n].mapin_rgbA_mapping, combiner.variable_A);
	// B
	pv = combiner_map_input_select3(combiner.stage[n].mapin_rgbB_input);
	c = combiner.stage[n].mapin_rgbB_component * 3;
	i = ~combiner.stage[n].mapin_rgbB_component & 1;
	for (d = 0; d < 3; d++) {
		combiner.variable_B[d] = pv[c];
		c = c + i;
	}
	combiner_map_input_function3(combiner.stage[n].mapin_rgbB_mapping, combiner.variable_B);
	// C
	pv = combiner_map_input_select3(combiner.stage[n].mapin_rgbC_input);
	c = combiner.stage[n].mapin_rgbC_component * 3;
	i = ~combiner.stage[n].mapin_rgbC_component & 1;
	for (d = 0; d < 3; d++) {
		combiner.variable_C[d] = pv[c];
		c = c + i;
	}
	combiner_map_input_function3(combiner.stage[n].mapin_rgbC_mapping, combiner.variable_C);
	// D
	pv = combiner_map_input_select3(combiner.stage[n].mapin_rgbD_input);
	c = combiner.stage[n].mapin_rgbD_component * 3;
	i = ~combiner.stage[n].mapin_rgbD_component & 1;
	for (d = 0; d < 3; d++) {
		combiner.variable_D[d] = pv[c];
		c = c + i;
	}
	combiner_map_input_function3(combiner.stage[n].mapin_rgbD_mapping, combiner.variable_D);
}

void nv2a_renderer::combiner_map_output(int stage_number)
{
	int n = stage_number;
	float *f;

	// rgb
	f = combiner_map_output_select3(combiner.stage[n].mapout_rgbAB_output);
	if (f) {
		f[0] = combiner.function_RGBop1[0];
		f[1] = combiner.function_RGBop1[1];
		f[2] = combiner.function_RGBop1[2];
	}
	f = combiner_map_output_select3(combiner.stage[n].mapout_rgbCD_output);
	if (f) {
		f[0] = combiner.function_RGBop2[0];
		f[1] = combiner.function_RGBop2[1];
		f[2] = combiner.function_RGBop2[2];
	}
	if ((combiner.stage[n].mapout_rgbAB_dotproduct | combiner.stage[n].mapout_rgbCD_dotproduct) == 0) {
		f = combiner_map_output_select3(combiner.stage[n].mapout_rgbSUM_output);
		if (f) {
			f[0] = combiner.function_RGBop3[0];
			f[1] = combiner.function_RGBop3[1];
			f[2] = combiner.function_RGBop3[2];
		}
	}
	// a
	f = combiner_map_output_select3(combiner.stage[n].mapout_aAB_output);
	if (f)
		f[3] = combiner.function_Aop1;
	f = combiner_map_output_select3(combiner.stage[n].mapout_aCD_output);
	if (f)
		f[3] = combiner.function_Aop2;
	f = combiner_map_output_select3(combiner.stage[n].mapout_aSUM_output);
	if (f)
		f[3] = combiner.function_Aop3;
}

void nv2a_renderer::combiner_map_final_input()
{
	int i, c, d;
	float *pv;

	// E
	pv = combiner_map_input_select3(combiner.final.mapin_rgbE_input);
	c = combiner.final.mapin_rgbE_component * 3;
	i = ~combiner.final.mapin_rgbE_component & 1;
	for (d = 0; d < 3; d++) {
		combiner.variable_E[d] = pv[c];
		c = c + i;
	}
	combiner_map_input_function3(combiner.final.mapin_rgbE_mapping, combiner.variable_E);
	// F
	pv = combiner_map_input_select3(combiner.final.mapin_rgbF_input);
	c = combiner.final.mapin_rgbF_component * 3;
	i = ~combiner.final.mapin_rgbF_component & 1;
	for (d = 0; d < 3; d++) {
		combiner.variable_F[d] = pv[c];
		c = c + i;
	}
	combiner_map_input_function3(combiner.final.mapin_rgbF_mapping, combiner.variable_F);
	// EF
	combiner.variable_EF[0] = combiner.variable_E[0] * combiner.variable_F[0];
	combiner.variable_EF[1] = combiner.variable_E[1] * combiner.variable_F[1];
	combiner.variable_EF[2] = combiner.variable_E[2] * combiner.variable_F[2];
	// sumclamp
	combiner.variable_sumclamp[0] = std::max(0.0f, combiner.register_spare0[0]) + std::max(0.0f, combiner.register_secondarycolor[0]);
	combiner.variable_sumclamp[1] = std::max(0.0f, combiner.register_spare0[1]) + std::max(0.0f, combiner.register_secondarycolor[1]);
	combiner.variable_sumclamp[2] = std::max(0.0f, combiner.register_spare0[2]) + std::max(0.0f, combiner.register_secondarycolor[2]);
	if (combiner.final.color_sum_clamp != 0) {
		combiner.variable_sumclamp[0] = std::min(combiner.variable_sumclamp[0], 1.0f);
		combiner.variable_sumclamp[1] = std::min(combiner.variable_sumclamp[1], 1.0f);
		combiner.variable_sumclamp[2] = std::min(combiner.variable_sumclamp[2], 1.0f);
	}
	// A
	pv = combiner_map_input_select3(combiner.final.mapin_rgbA_input);
	c = combiner.final.mapin_rgbA_component * 3;
	i = ~combiner.final.mapin_rgbA_component & 1;
	for (d = 0; d < 3; d++) {
		combiner.variable_A[d] = pv[c];
		c = c + i;
	}
	combiner_map_input_function3(combiner.final.mapin_rgbA_mapping, combiner.variable_A);
	// B
	pv = combiner_map_input_select3(combiner.final.mapin_rgbB_input);
	c = combiner.final.mapin_rgbB_component * 3;
	i = ~combiner.final.mapin_rgbB_component & 1;
	for (d = 0; d < 3; d++) {
		combiner.variable_B[d] = pv[c];
		c = c + i;
	}
	combiner_map_input_function3(combiner.final.mapin_rgbB_mapping, combiner.variable_B);
	// C
	pv = combiner_map_input_select3(combiner.final.mapin_rgbC_input);
	c = combiner.final.mapin_rgbC_component * 3;
	i = ~combiner.final.mapin_rgbC_component & 1;
	for (d = 0; d < 3; d++) {
		combiner.variable_C[d] = pv[c];
		c = c + i;
	}
	combiner_map_input_function3(combiner.final.mapin_rgbC_mapping, combiner.variable_C);
	// D
	pv = combiner_map_input_select3(combiner.final.mapin_rgbD_input);
	c = combiner.final.mapin_rgbD_component * 3;
	i = ~combiner.final.mapin_rgbD_component & 1;
	for (d = 0; d < 3; d++) {
		combiner.variable_D[d] = pv[c];
		c = c + i;
	}
	combiner_map_input_function3(combiner.final.mapin_rgbD_mapping, combiner.variable_D);
	// G
	combiner.variable_G = combiner_map_input_select(combiner.final.mapin_aG_input, 2 + combiner.final.mapin_aG_component);
}

void nv2a_renderer::combiner_final_output()
{
	// rgb
	combiner.output[0] = combiner.variable_A[0] * combiner.variable_B[0] + (1.0f - combiner.variable_A[0])*combiner.variable_C[0] + combiner.variable_D[0];
	combiner.output[1] = combiner.variable_A[1] * combiner.variable_B[1] + (1.0f - combiner.variable_A[1])*combiner.variable_C[1] + combiner.variable_D[1];
	combiner.output[2] = combiner.variable_A[2] * combiner.variable_B[2] + (1.0f - combiner.variable_A[2])*combiner.variable_C[2] + combiner.variable_D[2];
	combiner.output[0] = std::min(combiner.output[0], 1.0f);
	combiner.output[1] = std::min(combiner.output[1], 1.0f);
	combiner.output[2] = std::min(combiner.output[2], 1.0f);
	// a
	combiner.output[3] = combiner_map_input_function(combiner.final.mapin_aG_mapping, combiner.variable_G);
}

void nv2a_renderer::combiner_function_AB(float result[4])
{
	result[0] = combiner.variable_A[0] * combiner.variable_B[0];
	result[1] = combiner.variable_A[1] * combiner.variable_B[1];
	result[2] = combiner.variable_A[2] * combiner.variable_B[2];
}

void nv2a_renderer::combiner_function_AdotB(float result[4])
{
	result[0] = combiner.variable_A[0] * combiner.variable_B[0] + combiner.variable_A[1] * combiner.variable_B[1] + combiner.variable_A[2] * combiner.variable_B[2];
	result[1] = result[0];
	result[2] = result[0];
}

void nv2a_renderer::combiner_function_CD(float result[4])
{
	result[0] = combiner.variable_C[0] * combiner.variable_D[0];
	result[1] = combiner.variable_C[1] * combiner.variable_D[1];
	result[2] = combiner.variable_C[2] * combiner.variable_D[2];
}

void nv2a_renderer::combiner_function_CdotD(float result[4])
{
	result[0] = combiner.variable_C[0] * combiner.variable_D[0] + combiner.variable_C[1] * combiner.variable_D[1] + combiner.variable_C[2] * combiner.variable_D[2];
	result[1] = result[0];
	result[2] = result[0];
}

void nv2a_renderer::combiner_function_ABmuxCD(float result[4])
{
	if (combiner.register_spare0[3] >= 0.5f)
		combiner_function_AB(result);
	else
		combiner_function_CD(result);
}

void nv2a_renderer::combiner_function_ABsumCD(float result[4])
{
	result[0] = combiner.variable_A[0] * combiner.variable_B[0] + combiner.variable_C[0] * combiner.variable_D[0];
	result[1] = combiner.variable_A[1] * combiner.variable_B[1] + combiner.variable_C[1] * combiner.variable_D[1];
	result[2] = combiner.variable_A[2] * combiner.variable_B[2] + combiner.variable_C[2] * combiner.variable_D[2];
}

void nv2a_renderer::combiner_compute_rgb_outputs(int stage_number)
{
	int n = stage_number;
	int m;
	float biasrgb, scalergb;

	if (combiner.stage[n].mapout_rgb_bias)
		biasrgb = -0.5;
	else
		biasrgb = 0;
	switch (combiner.stage[n].mapout_rgb_scale) {
	case 0:
	default:
		scalergb = 1.0;
		break;
	case 1:
		scalergb = 2.0;
		break;
	case 2:
		scalergb = 4.0;
		break;
	case 3:
		scalergb = 0.5;
		break;
	}
	if (combiner.stage[n].mapout_rgbAB_dotproduct) {
		m = 1;
		combiner_function_AdotB(combiner.function_RGBop1);
	}
	else {
		m = 0;
		combiner_function_AB(combiner.function_RGBop1);
	}
	combiner.function_RGBop1[0] = std::max(std::min((combiner.function_RGBop1[0] + biasrgb) * scalergb, 1.0f), -1.0f);
	combiner.function_RGBop1[1] = std::max(std::min((combiner.function_RGBop1[1] + biasrgb) * scalergb, 1.0f), -1.0f);
	combiner.function_RGBop1[2] = std::max(std::min((combiner.function_RGBop1[2] + biasrgb) * scalergb, 1.0f), -1.0f);
	if (combiner.stage[n].mapout_rgbCD_dotproduct) {
		m = m | 1;
		combiner_function_CdotD(combiner.function_RGBop2);
	}
	else
		combiner_function_CD(combiner.function_RGBop2);
	combiner.function_RGBop2[0] = std::max(std::min((combiner.function_RGBop2[0] + biasrgb) * scalergb, 1.0f), -1.0f);
	combiner.function_RGBop2[1] = std::max(std::min((combiner.function_RGBop2[1] + biasrgb) * scalergb, 1.0f), -1.0f);
	combiner.function_RGBop2[2] = std::max(std::min((combiner.function_RGBop2[2] + biasrgb) * scalergb, 1.0f), -1.0f);
	if (m == 0) {
		if (combiner.stage[n].mapout_rgb_muxsum)
			combiner_function_ABmuxCD(combiner.function_RGBop3);
		else
			combiner_function_ABsumCD(combiner.function_RGBop3);
		combiner.function_RGBop3[0] = std::max(std::min((combiner.function_RGBop3[0] + biasrgb) * scalergb, 1.0f), -1.0f);
		combiner.function_RGBop3[1] = std::max(std::min((combiner.function_RGBop3[1] + biasrgb) * scalergb, 1.0f), -1.0f);
		combiner.function_RGBop3[2] = std::max(std::min((combiner.function_RGBop3[2] + biasrgb) * scalergb, 1.0f), -1.0f);
	}
}

void nv2a_renderer::combiner_compute_a_outputs(int stage_number)
{
	int n = stage_number;
	float biasa, scalea;

	if (combiner.stage[n].mapout_a_bias)
		biasa = -0.5;
	else
		biasa = 0;
	switch (combiner.stage[n].mapout_a_scale) {
	case 0:
	default:
		scalea = 1.0;
		break;
	case 1:
		scalea = 2.0;
		break;
	case 2:
		scalea = 4.0;
		break;
	case 3:
		scalea = 0.5;
		break;
	}
	combiner.function_Aop1 = combiner.variable_A[3] * combiner.variable_B[3];
	combiner.function_Aop1 = std::max(std::min((combiner.function_Aop1 + biasa) * scalea, 1.0f), -1.0f);
	combiner.function_Aop2 = combiner.variable_C[3] * combiner.variable_D[3];
	combiner.function_Aop2 = std::max(std::min((combiner.function_Aop2 + biasa) * scalea, 1.0f), -1.0f);
	if (combiner.stage[n].mapout_a_muxsum) {
		if (combiner.register_spare0[3] >= 0.5f)
			combiner.function_Aop3 = combiner.variable_A[3] * combiner.variable_B[3];
		else
			combiner.function_Aop3 = combiner.variable_C[3] * combiner.variable_D[3];
	}
	else
		combiner.function_Aop3 = combiner.variable_A[3] * combiner.variable_B[3] + combiner.variable_C[3] * combiner.variable_D[3];
	combiner.function_Aop3 = std::max(std::min((combiner.function_Aop3 + biasa) * scalea, 1.0f), -1.0f);
}

WRITE_LINE_MEMBER(nv2a_renderer::vblank_callback)
{
#ifdef LOG_NV2A
	printf("vblank_callback\n\r");
#endif
	if ((state == true) && (puller_waiting == 1)) {
		puller_waiting = 0;
		puller_timer_work(nullptr, 0);
	}
	if (state == true) {
		pcrtc[0x100 / 4] |= 1;
		pcrtc[0x808 / 4] |= 0x10000;
	}
	else {
		pcrtc[0x100 / 4] &= ~1;
		pcrtc[0x808 / 4] &= ~0x10000;
	}
	if (update_interrupts() == true)
		irq_callback(1); // IRQ 3
	else
		irq_callback(0); // IRQ 3
}

bool nv2a_renderer::update_interrupts()
{
	if (pcrtc[0x100 / 4] & pcrtc[0x140 / 4])
		pmc[0x100 / 4] |= 0x1000000;
	else
		pmc[0x100 / 4] &= ~0x1000000;
	if (pgraph[0x100 / 4] & pgraph[0x140 / 4])
		pmc[0x100 / 4] |= 0x1000;
	else
		pmc[0x100 / 4] &= ~0x1000;
	if (((pmc[0x100 / 4] & 0x7fffffff) && (pmc[0x140 / 4] & 1)) || ((pmc[0x100 / 4] & 0x80000000) && (pmc[0x140 / 4] & 2))) {
		// send interrupt
		return true;
	}
	else
		return false;
}

uint32_t nv2a_renderer::screen_update_callback(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
	if (displayedtarget != nullptr) {
		bitmap_rgb32 bm(displayedtarget, 640, 480, 640);
		uint32_t *dst = (uint32_t *)bitmap.raw_pixptr(0, 0);

		//printf("updatescreen %08X\n\r",pcrtc[0x800/4]);
		memcpy(dst, displayedtarget, bitmap.rowbytes()*bitmap.height());
	}
	return 0;
}

void nv2a_renderer::geforce_assign_object(address_space & space, uint32_t chanel, uint32_t subchannel, uint32_t address)
{
	int handle, objclass;

	handle = space.read_dword(address);
	handle = geforce_object_offset(handle);
#ifdef LOG_NV2A
	machine().logerror("  assign to subchannel %d object at %d", subchannel, handle);
#endif
	channel[chanel][subchannel].object.objhandle = handle;
	handle = ramin[handle / 4];
	objclass = handle & 0xff;
#ifdef LOG_NV2A
	machine().logerror(" class %03X\n", objclass);
#endif
	channel[chanel][subchannel].object.objclass = objclass;
}

TIMER_CALLBACK_MEMBER(nv2a_renderer::puller_timer_work)
{
	int chanel;
	int method, count;
	uint32_t *dmaput, *dmaget;
	uint32_t cmd, cmdtype;
	int countlen;
	int ret;
	address_space *space = puller_space;
	uint32_t subch;

	for (chanel = 0; chanel < 32; chanel++) {
		dmaput = &channel[chanel][0].regs[0x40 / 4];
		dmaget = &channel[chanel][0].regs[0x44 / 4];
		while (*dmaget != *dmaput) {
			cmd = space->read_dword(*dmaget);
			*dmaget += 4;
			cmdtype = geforce_commandkind(cmd);
			switch (cmdtype)
			{
			case 6: // jump
	#ifdef LOG_NV2A
				machine().logerror("jump dmaget %08X", *dmaget);
	#endif
				*dmaget = cmd & 0xfffffffc;
	#ifdef LOG_NV2A
				machine().logerror(" -> %08X\n\r", *dmaget);
	#endif
				break;
			case 0: // increasing method
				method = (cmd >> 2) & 2047; // method*4 is address // if method >= 0x40 send it to assigned object
				subch = (cmd >> 13) & 7;
				count = (cmd >> 18) & 2047;
				if ((method == 0) && (count == 1)) {
					geforce_assign_object(*space, chanel, subch, *dmaget);
					*dmaget += 4;
				}
				else {
	#ifdef LOG_NV2A
					machine().logerror("  subch. %d method %04x offset %04x count %d\n", subch, method, method * 4, count);
	#endif
					ret = 0;
					while (count > 0) {
						countlen = 1;
						ret=geforce_exec_method(*space, chanel, subch, method, *dmaget, countlen);
						count--;
						method++;
						*dmaget += 4;
						if (ret != 0)
							break;
					}
					if (ret != 0) {
						puller_timer->enable(false);
						puller_waiting = ret;
						return;
					}
				}
				break;
			case 5: // non-increasing method
				method = (cmd >> 2) & 2047;
				subch = (cmd >> 13) & 7;
				count = (cmd >> 18) & 2047;
				if ((method == 0) && (count == 1)) {
					geforce_assign_object(*space, chanel, subch, *dmaget);
					*dmaget += 4;
				}
				else {
	#ifdef LOG_NV2A
					machine().logerror("  subch. %d method %04x offset %04x count %d\n", subch, method, method * 4, count);
	#endif
					while (count > 0) {
						countlen = count;
						ret=geforce_exec_method(*space, chanel, subch, method, *dmaget, countlen);
						*dmaget += 4 * (count - countlen);
						count = countlen;
					}
				}
				break;
			case 3: // long non-increasing method
				method = (cmd >> 2) & 2047;
				subch = (cmd >> 13) & 7;
				count = space->read_dword(*dmaget);
				*dmaget += 4;
				if ((method == 0) && (count == 1)) {
					geforce_assign_object(*space, chanel, subch, *dmaget);
					*dmaget += 4;
				}
				else {
	#ifdef LOG_NV2A
					machine().logerror("  subch. %d method %04x offset %04x count %d\n", subch, method, method * 4, count);
	#endif
					while (count > 0) {
						countlen = count;
						ret=geforce_exec_method(*space, chanel, subch, method, *dmaget, countlen);
						*dmaget += 4 * (count - countlen);
						count = countlen;
					}
				}
				break;
			default:
				machine().logerror("  unimplemented command %08X\n", cmd);
			}
		}
	}
}

READ32_MEMBER(nv2a_renderer::geforce_r)
{
	static int x, ret;

	ret = 0;
	if (offset == 0x1804f6) {
		x = x ^ 0x08080808;
		ret = x;
	}
	if ((offset >= 0x00100000 / 4) && (offset < 0x00101000 / 4)) {
		//machine().logerror("NV_2A: read 100000[%06X] mask %08X value %08X\n",offset*4-0x00101000,mem_mask,ret);
		if (offset == 0x100200 / 4)
			return 3;
	}
	else if ((offset >= 0x00101000 / 4) && (offset < 0x00102000 / 4)) {
		//machine().logerror("NV_2A: read STRAPS[%06X] mask %08X value %08X\n",offset*4-0x00101000,mem_mask,ret);
	}
	else if ((offset >= 0x00002000 / 4) && (offset < 0x00004000 / 4)) {
		ret = pfifo[offset - 0x00002000 / 4];
		// PFIFO.CACHE1.STATUS or PFIFO.RUNOUT_STATUS
		if ((offset == 0x3214 / 4) || (offset == 0x2400 / 4))
			ret = 0x10;
		//machine().logerror("NV_2A: read PFIFO[%06X] value %08X\n",offset*4-0x00002000,ret);
	}
	else if ((offset >= 0x00700000 / 4) && (offset < 0x00800000 / 4)) {
		ret = ramin[offset - 0x00700000 / 4];
		//machine().logerror("NV_2A: read PRAMIN[%06X] value %08X\n",offset*4-0x00700000,ret);
	}
	else if ((offset >= 0x00400000 / 4) && (offset < 0x00402000 / 4)) {
		ret = pgraph[offset - 0x00400000 / 4];
		//machine().logerror("NV_2A: read PGRAPH[%06X] value %08X\n",offset*4-0x00400000,ret);
	}
	else if ((offset >= 0x00600000 / 4) && (offset < 0x00601000 / 4)) {
		ret = pcrtc[offset - 0x00600000 / 4];
		//machine().logerror("NV_2A: read PCRTC[%06X] value %08X\n",offset*4-0x00600000,ret);
	}
	else if ((offset >= 0x00000000 / 4) && (offset < 0x00001000 / 4)) {
		ret = pmc[offset - 0x00000000 / 4];
		//machine().logerror("NV_2A: read PMC[%06X] value %08X\n",offset*4-0x00000000,ret);
	}
	else if ((offset >= 0x00800000 / 4) && (offset < 0x00900000 / 4)) {
		// 32 channels size 0x10000 each, 8 subchannels per channel size 0x2000 each
		int chanel, subchannel, suboffset;

		suboffset = offset - 0x00800000 / 4;
		chanel = (suboffset >> (16 - 2)) & 31;
		subchannel = (suboffset >> (13 - 2)) & 7;
		suboffset = suboffset & 0x7ff;
		if (suboffset < 0x80 / 4)
			ret = channel[chanel][subchannel].regs[suboffset];
		//machine().logerror("NV_2A: read channel[%02X,%d,%04X]=%08X\n",chanel,subchannel,suboffset*4,ret);
		return ret;
	}
	//machine().logerror("NV_2A: read at %08X mask %08X value %08X\n",0xfd000000+offset*4,mem_mask,ret);
	return ret;
}

WRITE32_MEMBER(nv2a_renderer::geforce_w)
{
	uint32_t old;
	bool update_int;

	update_int = false;
	if ((offset >= 0x00101000 / 4) && (offset < 0x00102000 / 4)) {
		//machine().logerror("NV_2A: write STRAPS[%06X] mask %08X value %08X\n",offset*4-0x00101000,mem_mask,data);
	}
	else if ((offset >= 0x00002000 / 4) && (offset < 0x00004000 / 4)) {
		int e = offset - 0x00002000 / 4;
		if (e >= (sizeof(pfifo) / sizeof(uint32_t)))
			return;
		COMBINE_DATA(pfifo + e);
		//machine().logerror("NV_2A: read PFIFO[%06X]=%08X\n",offset*4-0x00002000,data & mem_mask); // 2210 pfifo ramht & 1f0 << 12
	}
	else if ((offset >= 0x00700000 / 4) && (offset < 0x00800000 / 4)) {
		int e = offset - 0x00700000 / 4;
		if (e >= (sizeof(ramin) / sizeof(uint32_t)))
			return;
		COMBINE_DATA(ramin + e);
		//machine().logerror("NV_2A: write PRAMIN[%06X]=%08X\n",offset*4-0x00700000,data & mem_mask);
	}
	else if ((offset >= 0x00400000 / 4) && (offset < 0x00402000 / 4)) {
		int e = offset - 0x00400000 / 4;
		if (e >= (sizeof(pgraph) / sizeof(uint32_t)))
			return;
		old = pgraph[e];
		COMBINE_DATA(pgraph + e);
		if (e == 0x100 / 4) {
			pgraph[e] = old & ~data;
			if (data & 1)
				pgraph[0x108 / 4] = 0;
			update_int = true;
		}
		if (e == 0x140 / 4)
			update_int = true;
		if (e == 0x720 / 4) {
			if ((data & 1) && (puller_waiting == 2)) {
				puller_waiting = 0;
				puller_timer->enable();
				puller_timer->adjust(attotime::zero);
			}
		}
		if ((e >= 0x900 / 4) && (e < 0xa00 / 4))
			pgraph[e] = 0;
		//machine().logerror("NV_2A: write PGRAPH[%06X]=%08X\n",offset*4-0x00400000,data & mem_mask);
	}
	else if ((offset >= 0x00600000 / 4) && (offset < 0x00601000 / 4)) {
		int e = offset - 0x00600000 / 4;
		if (e >= (sizeof(pcrtc) / sizeof(uint32_t)))
			return;
		old = pcrtc[e];
		COMBINE_DATA(pcrtc + e);
		if (e == 0x100 / 4) {
			pcrtc[e] = old & ~data;
			update_int = true;
		}
		if (e == 0x140 / 4)
			update_int = true;
		if (e == 0x800 / 4) {
			displayedtarget = (uint32_t *)direct_access_ptr(pcrtc[e]);
#ifdef LOG_NV2A
			printf("crtc buffer %08X\n\r", data);
#endif
		}
		//machine().logerror("NV_2A: write PCRTC[%06X]=%08X\n",offset*4-0x00600000,data & mem_mask);
	}
	else if ((offset >= 0x00000000 / 4) && (offset < 0x00001000 / 4)) {
		int e = offset - 0x00000000 / 4;
		if (e >= (sizeof(pmc) / sizeof(uint32_t)))
			return;
		COMBINE_DATA(pmc + e);
		//machine().logerror("NV_2A: write PMC[%06X]=%08X\n",offset*4-0x00000000,data & mem_mask);
	}
	else if ((offset >= 0x00800000 / 4) && (offset < 0x00900000 / 4)) {
		// 32 channels size 0x10000 each, 8 subchannels per channel size 0x2000 each
		int chanel, subchannel, suboffset;
		//int method, count, handle, objclass;

		suboffset = offset - 0x00800000 / 4;
		chanel = (suboffset >> (16 - 2)) & 31;
		subchannel = (suboffset >> (13 - 2)) & 7;
		suboffset = suboffset & 0x7ff;
		//machine().logerror("NV_2A: write channel[%02X,%d,%04X]=%08X\n",chanel,subchannel,suboffset*4,data & mem_mask);
		COMBINE_DATA(&channel[chanel][subchannel].regs[suboffset]);
		if (suboffset >= 0x80 / 4)
			return;
		if ((suboffset == 0x40 / 4) || (suboffset == 0x44 / 4)) { // DMA_PUT or DMA_GET
			uint32_t *dmaput, *dmaget;

			dmaput = &channel[chanel][0].regs[0x40 / 4];
			dmaget = &channel[chanel][0].regs[0x44 / 4];
			//printf("dmaget %08X dmaput %08X\n\r",*dmaget,*dmaput);
			if (((*dmaput == 0x048cf000) && (*dmaget == 0x07f4d000)) || // only for outr2
				((*dmaput == 0x045cd000) && (*dmaget == 0x07f4d000)) || // only for scg06nt
				((*dmaput == 0x0494c000) && (*dmaget == 0x07f4d000)) || // only for wangmid
				((*dmaput == 0x05acd000) && (*dmaget == 0x07f4d000)) || // only for ghostsqu
				((*dmaput == 0x0574d000) && (*dmaget == 0x07f4d000)) || // only for mj2c
				((*dmaput == 0x07ca3000) && (*dmaget == 0x07f4d000)) || // only for hotd3
				((*dmaput == 0x063cd000) && (*dmaget == 0x07f4d000)) || // only for vcop3
				((*dmaput == 0x07f4f000) && (*dmaget == 0x07f4d000)) || // only for ccfboxa
				((*dmaput == 0x07dca000) && (*dmaget == 0x07f4d000))) // only for crtaxihr
			{
				*dmaget = *dmaput;
				puller_waiting = 0;
				puller_timer->enable(false);
				return;
			}
			if (*dmaget != *dmaput) {
				if (puller_waiting == 0) {
					puller_space = &space;
					puller_timer->enable();
					puller_timer->adjust(attotime::zero);
				}
			}
		}
	}
	//else
	//      machine().logerror("NV_2A: write at %08X mask %08X value %08X\n",0xfd000000+offset*4,mem_mask,data);
	if (update_int == true) {
		if (update_interrupts() == true)
			irq_callback(1); // IRQ 3
		else
			irq_callback(0); // IRQ 3
	}
}

void nv2a_renderer::savestate_items()
{
}

void nv2a_renderer::start(address_space *cpu_space)
{
	basemempointer = (uint8_t *)cpu_space->get_read_ptr(0);
	topmempointer = basemempointer + 512 * 1024 * 1024 - 1;
	puller_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(nv2a_renderer::puller_timer_work), this), (void *)"NV2A Puller Timer");
	puller_timer->enable(false);
}