2015-10-20 9 views
6

नमूना कार्यक्रम पर पूर्ण स्क्रीन समर्थन जोड़ने के दौरान, मैंने इस छोटे से परेशान व्यवहार पर ठोकर खाई।डायरेक्टएक्स 11 स्वैपचेन और खिड़की पूर्णस्क्रीन स्थिति खोने

एक पूर्ण स्क्रीन विंडो बनाना काम करता है, लेकिन जैसे ही मैं अपनी पूर्णस्क्रीन विंडो वाली आउटपुट पर किसी भी विंडो (किसी अन्य एप्लिकेशन से) ले जाता हूं, यह स्वचालित रूप से विंडो पर वापस स्विच करता है।

क्या इस व्यवहार को रोकने के लिए कोई तरीका है (इसलिए पूर्ण स्क्रीन विंडो खिड़की पर वापस नहीं जाती है)?

एक संदर्भ के रूप में, यह एक छोटा सा स्टैंडअलोन उदाहरण है (इसलिए समस्या को आसानी से दोहराया जा सकता है)।

यदि यह उपयोगी है, तो भी मैं विंडोज 8.1 पर चल रहा हूं।

मैं पहले से ही,, WindowAssociationFlags और SwapChainFlags बदलने की कोशिश की दोनों कोई सफलता के साथ त्यागें के बजाय FlipSequential का उपयोग कर के रूप में ही

SharpDX.DXGI.Factory2 factory = new SharpDX.DXGI.Factory2(); 
SharpDX.DXGI.Adapter adapter = factory.GetAdapter(0); 

var renderForm1 = new RenderForm("Form 1"); 
factory.MakeWindowAssociation(renderForm1.Handle, SharpDX.DXGI.WindowAssociationFlags.IgnoreAll); 

Device device = new Device(adapter, DeviceCreationFlags.BgraSupport); 

SharpDX.DXGI.SwapChainDescription sd = new SharpDX.DXGI.SwapChainDescription() 
{ 
    BufferCount = 2, 
    ModeDescription = new SharpDX.DXGI.ModeDescription(0, 0, new SharpDX.DXGI.Rational(50, 1), SharpDX.DXGI.Format.R8G8B8A8_UNorm), 
    IsWindowed = true, 
    OutputHandle = renderForm1.Handle, 
    SampleDescription = new SharpDX.DXGI.SampleDescription(1,0), 
    SwapEffect = SharpDX.DXGI.SwapEffect.Discard, 
    Usage = SharpDX.DXGI.Usage.RenderTargetOutput, 
    Flags = SharpDX.DXGI.SwapChainFlags.None 
}; 

var swapChain1 = new SharpDX.DXGI.SwapChain(factory, device, sd); 

renderForm1.Left = 1922; //Just hardcoded here to move window to second screen 
renderForm1.Width = 1920; 
renderForm1.Height = 1080; 
renderForm1.FormBorderStyle = FormBorderStyle.None; 

swapChain1.SetFullscreenState(true, null); 
swapChain1.ResizeBuffers(2, 1920, 1080, SharpDX.DXGI.Format.R8G8B8A8_UNorm, SharpDX.DXGI.SwapChainFlags.AllowModeSwitch); 

var resource = Texture2D.FromSwapChain<Texture2D>(swapChain1, 0); 
var renderView = new RenderTargetView(device, resource); 

RenderLoop.Run(renderForm1,() => 
{ 
    device.ImmediateContext.ClearRenderTargetView(renderView, new SharpDX.Color4(1, 0, 0, 1)); 
    swapChain1.Present(1, SharpDX.DXGI.PresentFlags.None); 
}); 

संपादित करें: मैं भी Microsoft से एक C++ नमूना (बस ले लिया इंटरनेट 11 बुनियादी ट्यूटोरियल की कोशिश की और पूर्ण स्क्रीन स्विच जोड़ा गया), यह एक ही व्यवहार की ओर जाता है, इसलिए यह एक SharpDX विशिष्ट समस्या नहीं है।

मैंने संदेश लूप देखा, और एक बार ऐसा होने पर, पहले पूर्णस्क्रीन मोड को वापस विंडो में बदल दिया जाता है, और मुझे WM_DISPLAYCHANGE संदेश प्राप्त होता है)।

उत्तर

3

यह अपेक्षित व्यवहार की तरह लगता है। यदि आपके पास पूर्ण स्क्रीन 'अनन्य' मोड स्वैपचेन है और संबंधित विंडो फोकस खो देती है, तो सिस्टम स्वचालित रूप से पूर्ण स्क्रीन मोड से एप्लिकेशन को पर डिज़ाइन द्वारा स्विच करता है।

एक एकल मॉनीटर के साथ, यह अधिकतर तब तक काम करता है जब तक आपके पास प्रदर्शन को भरने के लिए आपके एप्लिकेशन की विंडो आकार का आकार होता है। उपयोगकर्ता आपकी विंडो के फोकस को बदलने के लिए माउस का उपयोग नहीं कर सकते हैं, और इसे फोकस स्विच करने के लिए ALT + TAB जैसे कुछ की आवश्यकता है।

एकाधिक मॉनीटर के साथ, यह एक वास्तविक समस्या है। यदि आप किसी अन्य डिस्प्ले पर किसी अन्य विंडो पर क्लिक करते हैं, तो आपका ऐप फोकस खो देता है और पूर्ण स्क्रीन मोड फिर से स्विच हो जाता है। ऐसी सीमाएं भी हैं जो आपको एक से अधिक मॉनीटर पर पूर्ण स्क्रीन 'अनन्य' मोड सेट करने से रोकती हैं।

इसके अलावा, विंडोज विस्टा पर या बाद में 'अनन्य' मोड की धारणा एक भ्रम है: GPU हमेशा किसी भी तरह साझा किया जाता है। 'फोकस' एप्लिकेशन को प्राथमिकता मिलती है चाहे वह एक पूर्ण स्क्रीन या खिड़की वाली स्वैप श्रृंखला हो।

आप एक पूर्ण स्क्रीन शैली के अनुभव के लिए तीन विकल्प एक विंडोज डेस्कटॉप एप्लिकेशन के लिए:

  1. एक खिड़की, प्रदर्शन को भरने के लिए प्रदर्शन मोड की स्थापना के साथ साथ आकार के साथ परंपरागत पूर्ण स्क्रीन 'विशेष' मोड का उपयोग करें जो उपयोगकर्ता ने विंडोज के लिए सामान्य रूप से सेट नहीं किया हो सकता है। यहां आपके पास IsWindowed = false है।
  2. आप पूर्ण प्रदर्शन को भरने के लिए विंडो आकार सेट करते हैं (यानी अधिकतम)। आप विंडोज शैलियों का उपयोग यह सुनिश्चित करने के लिए कर सकते हैं कि विंडो में कोई फ्रेम न हो जिसके परिणामस्वरूप पूर्ण स्क्रीन शैली का अनुभव हो (WS_POPUP)। यहां आपके पास IsWindowed = true है, और आपको DXGI_MWA_NO_ALT_ENTER सेट करना सुनिश्चित करना चाहिए ताकि आप DXGI को 1 केस का उपयोग करने की अनुमति दे सकें।
  3. आप IsWindowed = true के साथ 2 के समान कर सकते हैं और स्क्रीन से मिलान करने के लिए सीमाहीन खिड़की का आकार बदल सकते हैं, लेकिन आप डिस्प्ले मोड को सिस्टम डिफ़ॉल्ट के अलावा किसी अन्य चीज़ में बदल सकते हैं।इसे आमतौर पर 'नकली पूर्ण स्क्रीन' के रूप में जाना जाता है। जब भी आप एप्लिकेशन से बाहर निकलेंगे तो डिस्प्ले मोड वापस बदल जाएगा।

1 में सभी में बहु-कार्य और ध्यान केंद्रित करने वाली सभी समस्याएं हैं जिन्हें हमने अभी वर्णित किया है। 2 और 3 सिस्टम अधिसूचनाओं और अन्य पॉप-अप को गेम पर दिखाने के लिए अनुमति देते हैं और मोड स्विच को मजबूर नहीं करते हैं। 2 और 3 मल्टी-मॉनिटर सेटअप में भी बहुत बेहतर काम करते हैं जहां आप एक गेम पर अपना गेम खेल सकते हैं और अन्य डिस्प्ले पर अन्य ऐप्स का उपयोग कर सकते हैं। मल्टी-टास्किंग के लिए ज्यादातर लोग फ्रेम सीमा के साथ क्लासिक विंडो शैली पसंद करते हैं।

विंडोज स्टोर यूडब्ल्यूपी पूर्ण स्क्रीन मोड की धारणा मूल रूप से 2 ऊपर की तरह है। आप एक यूडब्ल्यूपी के साथ प्रदर्शन मोड नहीं बदल सकते हैं।

एक पूर्ण-स्क्रीन सेटअप डिबग करना काफी चुनौतीपूर्ण है। एकाधिक मॉनीटर के साथ, 2 और 3 अन्य स्क्रीन पर आपके डीबगर के साथ काम कर सकते हैं। सच्चे पूर्ण-स्क्रीन विशेष मोड के लिए, वास्तव में एकमात्र विकल्प किसी अन्य पीसी से रिमोट डीबगिंग का उपयोग करना है।

1 और 3 के साथ एक और मुद्दा यह है कि आप डिस्प्ले मोड को उस चीज़ पर सेट कर सकते हैं जो उपयोगकर्ता को यूआई के साथ सिस्टम छोड़ने के बिना सिंक्रनाइज़ नहीं करेगा और बाहर निकलने का कोई तरीका नहीं है। आदर्श रूप से सही ड्राइवर सेटअप के साथ, DXGI गणना सूची में असमर्थित मोड नहीं होते हैं, लेकिन यह कुछ पता होना चाहिए। इस कारण से, डिस्प्ले मोड का चयन करने के लिए आपके यूआई में टाइमआउट होना चाहिए और आपको यह सुनिश्चित करना चाहिए कि कीबोर्ड में एप्लिकेशन को निरस्त करने का एक उचित तरीका है यदि डिस्प्ले मोड भविष्य में किसी बिंदु पर सिंक हो जाता है। जैसा कि हम ऊपर 2 में करते हैं, मौजूदा डिस्प्ले मोड का उपयोग करना हमेशा सबसे सुरक्षित विकल्प है।

उपरोक्त पूर्ण स्क्रीन अनन्य मोड (1) का उपयोग करने का मुख्य कारण बैकबफर/फ्रंटबफर के 'ब्लिट' के बजाय 'फ्लिप' प्राप्त करने का प्रयास करना है। अधिकांश आधुनिक प्रणालियों के लिए, यह एक नगण्य प्रदर्शन अंतर है। इसका उपयोग करने के दर्द के माध्यम से जाने का दूसरा कारण एसएलआई/क्रॉसफायर बहु-जीपीयू प्रतिपादन के लिए एक ही डिस्प्ले पर जा रहा है। वास्तव में उस परिदृश्य को काम करने के लिए कई अन्य अनुकूलन आवश्यक हैं, और यह बहुत विशिष्ट है। आपको विवरण के लिए विक्रेता अनुकूलन मार्गदर्शिकाएं तलाशनी चाहिए।

अधिकांश आधुनिक गेम पूर्ण स्क्रीन 'अनन्य' मोड की बजाय नकली पूर्ण स्क्रीन का उपयोग करने के लिए डिफ़ॉल्ट हैं। वे एक सच्चे विंडो वाले मोड का उपयोग करने की क्षमता प्रदान करते हैं क्योंकि कई उपयोगकर्ता खेलते समय बहु-कार्य करने में सक्षम होना चाहते हैं (जैसे संकेत ऑनलाइन देख रहे हैं, आईएम या बाहरी वॉयस चैट आदि का उपयोग करें)। एएए विंडोज डेस्कटॉप गेम जो एसएलआई/क्रॉसफायर के लिए ट्यूनेड उच्च-प्रदर्शन गेमिंग का समर्थन करना चाहते हैं, एक पूर्ण स्क्रीन 'अनन्य' मोड प्रदान करेगा, लेकिन इसके लिए कुछ काम करने की आवश्यकता है और कुछ डीएक्सजीआई कोड की तुलना में अधिक काम करने की आवश्यकता है।

DXGI Overview और DirectX Graphics Infrastructure (DXGI): Best Practices

+0

जिज्ञासा (विंडोज 8.1 या विंडोज 10 सोचने) से महान विस्तृत उत्तर के लिए धन्यवाद, क्या आपको डायरेक्टएक्स 9 पूर्ण स्क्रीन का उपयोग करके एक ही व्यवहार का सामना करना पड़ेगा (नहीं कि मैं इसे वापस रोल करने की योजना बना रहा हूं, लेकिन इसके बारे में उत्सुक हूं)? – catflier

+0

मुझे लगता है कि डायरेक्ट 3 डी 9 पूर्ण स्क्रीन मोड के अनुकरण के तरीके में कुछ quirks हैं - याद रखें कि "खोया डिवाइस" परिदृश्य वास्तव में Windows Vista + पर मौजूद नहीं है, इसलिए यह व्यवहार भी नकल किया जाता है - लेकिन मुझे विश्वास है कि यह मूल रूप से है वैसी ही स्तिथि। –

+0

डिफ़ॉल्ट रूप से dx9 में यह वास्तव में और भी बदतर है, जैसे ही यह ध्यान केंद्रित करता है, यह स्वयं को छुपाता है, लेकिन कम से कम इसे आसानी से धोखा दिया जा सकता है, ऐसा लगता है कि अब एकमात्र तरीका संसाधन को वापस साझा किया जाएगा ... – catflier

2

देखें कई प्रयासों और परीक्षणों के बाद, यहाँ विभिन्न समाधान मैं इस्तेमाल किया जाता है, कोई भी आदर्श हैं, लेकिन सभी किसी तरह एक मोड परिवर्तन हो रही से बेहतर हैं।

1/पूर्ण स्क्रीन विंडो के बीच में कर्सर फोर्स, फिर से नियंत्रण प्राप्त करने के लिए कीबोर्ड शॉर्टकट के साथ। यह आदर्श नहीं है क्योंकि हम अपना हिस्सा चलते समय वास्तव में कुछ भी नहीं कर सकते हैं, लेकिन कम से कम आकस्मिक "आपदा क्लिक" को रोकता है। यह कीबोर्ड बातचीत को भी रोकता नहीं है।

2/साझा किए गए बनावट के साथ एक डीएक्स 9 रेंडरर का उपयोग करें। डीएक्स 9 स्वैपचेन के पास डेस्कटॉप पर सेट की मूल विंडो हो सकती है, इसलिए किसी और चीज पर जाने पर यह फोकस नहीं खोता है। शीर्ष पर एक केंद्रित खिड़की रखने के दौरान इसे देखते हुए छोटी सीमाएं दिखाई देती हैं, लेकिन यह सबकुछ खोने से थोड़ा अधिक स्वीकार्य है। भविष्य का सबूत नहीं है लेकिन अनुमान थोड़ी देर के लिए वास्तविक रहेगा।

3 विंडोज 7 और अक्षम DWM सेवा पर/रहें:

अब और Windows 8 में काम नहीं करता है, लेकिन अपने प्रयोग के मामले में के बाद से सबसे अधिक मीडिया कंपनियों मैं के लिए काम विंडोज 7 पर अभी भी कर रहे हैं, यह एक मान्य रहता है कम से कम 5 से 10 साल के लिए समाधान।

4/अग्रभूमि

पर DX11 विंडो बल मूल रूप से लगातार SetForegroundWindow फोन फोकस लेने के लिए एक और खिड़की से बचने के लिए।

5/प्रस्तुतिकरण स्तर पर मोड स्विच रोकें।

के बाद से अपने आवेदन पर मैं जब प्रस्तुति होती है, तो मैं निम्नलिखित दिनचर्या का उपयोग करें (से पहले वर्तमान कॉल करने के लिए) के लिए उपयोग मिल गया

जाओ अग्रभूमि विंडो हैंडल (GetForegroundWindow का प्रयोग करके), अग्रभूमि संभाल हमारे फुलस्क्रीन खिड़की है, तो बस सामान्य के रूप में वर्तमान कॉल करें।

यदि फोरग्राउंड हैंडल हमारी पूर्णस्क्रीन विंडो नहीं है, तो निम्न कार्य करें। कृपया ध्यान दें कि दृश्यता जांच की आवश्यकता नहीं है, क्योंकि यहां तक ​​कि एक अदृश्य ओवरलैपिंग विंडो भी एक पूर्ण स्क्रीन हानि का कारण बन जाएगी! (गंभीरता से, यह इतना बुरा है ...)

- अगर हमारी अग्रभूमि विंडो मॉनिटर के साथ ओवरलैप हो जाती है तो सत्यापित करें: सीमाएं प्राप्त करने के लिए GetWindowRect पर कॉल करें और मॉनिटर स्थान के साथ छेड़छाड़ करें।

वैकल्पिक रूप से, DXGI_PRESENT_TEST ध्वज के साथ स्वैपचैन पर वर्तमान कॉल करें। एक खिड़की अतिव्यापी है, तो वर्तमान कॉल DXGI_STATUS_OCCLUDED

वापस आ जाएगी एक खिड़की overlaps, तो या तो इसे छुपाना या एक और मॉनिटर में इसे स्थानांतरित (कहीं तो यह ओवरलैप नहीं करता है): ShowWindow और SetWindowPos इस कार्य के लिए aperfect फिट हैं।

उस लूप में टेस्ट वर्तमान कॉल दोहराएं जब तक कि यह अवरुद्ध स्थिति वापस नहीं लौटाता (यह महत्वपूर्ण है, क्योंकि विंडोज़ ने संदेशों को तुरंत संसाधित नहीं किया हो सकता है); एक बार घुमावदार ध्वज चला गया है, सामान्य के रूप में वर्तमान कॉल करें।

संबंधित मुद्दे